ia64/xen-unstable

changeset 13223:a8b2738a6f7f

[HVM] Fix HPET timer to support 8-byte accesses, erroneous updates
to read-only bits, etc.
Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@localhost.localdomain
date Fri Dec 29 14:12:55 2006 +0000 (2006-12-29)
parents 98271ea55d94
children 25723963a6b6
files xen/arch/x86/hvm/hpet.c xen/include/asm-x86/hvm/vpt.h
line diff
     1.1 --- a/xen/arch/x86/hvm/hpet.c	Fri Dec 29 13:02:19 2006 +0000
     1.2 +++ b/xen/arch/x86/hvm/hpet.c	Fri Dec 29 14:12:55 2006 +0000
     1.3 @@ -1,6 +1,7 @@
     1.4  /*
     1.5 - * hpet.c: emulating HPET in Xen
     1.6 + * hpet.c: HPET emulation for HVM guests.
     1.7   * Copyright (c) 2006, Intel Corporation.
     1.8 + * Copyright (c) 2006, Keir Fraser <keir@xensource.com>
     1.9   *
    1.10   * This program is free software; you can redistribute it and/or modify it
    1.11   * under the terms and conditions of the GNU General Public License,
    1.12 @@ -42,19 +43,7 @@
    1.13  #define HPET_T2_CFG     0x140
    1.14  #define HPET_T2_CMP     0x148
    1.15  #define HPET_T2_ROUTE   0x150
    1.16 -#define HPET_T3_CFG     0x158 /* not supported now*/
    1.17 -
    1.18 -#define HPET_REV                0x01ULL
    1.19 -#define HPET_NUMBER            0x200ULL /* 3 timers */
    1.20 -#define HPET_COUNTER_SIZE_CAP 0x2000ULL
    1.21 -#define HPET_LEG_RT_CAP       0x8000ULL
    1.22 -#define HPET_VENDOR_8086  0x80860000ULL
    1.23 -
    1.24 -/* 64bit main counter; 3 timers supported now;
    1.25 -   LegacyReplacemen Route supported.           */
    1.26 -#define HPET_CAP_ID_REG \
    1.27 -    (HPET_REV | HPET_NUMBER | HPET_COUNTER_SIZE_CAP | \
    1.28 -     HPET_LEG_RT_CAP | HPET_VENDOR_8086)
    1.29 +#define HPET_T3_CFG     0x160
    1.30  
    1.31  #define HPET_CFG_ENABLE          0x001
    1.32  #define HPET_CFG_LEGACY          0x002
    1.33 @@ -65,6 +54,7 @@
    1.34  #define HPET_TN_PERIODIC_CAP     0x010
    1.35  #define HPET_TN_SETVAL           0x040
    1.36  #define HPET_TN_32BIT            0x100
    1.37 +#define HPET_TN_SIZE_CAP         0x200
    1.38  #define HPET_TN_INT_ROUTE_MASK  0x3e00
    1.39  #define HPET_TN_INT_ROUTE_SHIFT      9
    1.40  #define HPET_TN_INT_ROUTE_CAP_SHIFT 32
    1.41 @@ -77,16 +67,11 @@
    1.42  #define HPET_TN_INT_ROUTE_CAP_MASK (0xffffffffULL \
    1.43                      << HPET_TN_INT_ROUTE_CAP_SHIFT)
    1.44  
    1.45 -#define HPET_TIMER_CMP32_DEFAULT 0xffffffffULL
    1.46 -#define HPET_TIMER_CMP64_DEFAULT 0xffffffffffffffffULL
    1.47 -#define HPET_TN_SIZE_CAP         (1 << 5)
    1.48 -
    1.49  #define hpet_tick_to_ns(h, tick) ((s_time_t)(tick)*S_TO_NS/h->tsc_freq)
    1.50  #define timer_config(h, n)       (h->hpet.timers[n].config)
    1.51  #define timer_enabled(h, n)      (timer_config(h, n) & HPET_TN_ENABLE)
    1.52  #define timer_is_periodic(h, n)  (timer_config(h, n) & HPET_TN_PERIODIC)
    1.53  #define timer_is_32bit(h, n)     (timer_config(h, n) & HPET_TN_32BIT)
    1.54 -#define timer_period_cap(h, n)   (timer_config(h, n) & HPET_TN_PERIODIC_CAP)
    1.55  #define hpet_enabled(h)          (h->hpet.config & HPET_CFG_ENABLE)
    1.56  #define timer_level(h, n)        (timer_config(h, n) & HPET_TN_INT_TYPE_LEVEL)
    1.57  
    1.58 @@ -97,72 +82,26 @@
    1.59      ((timer_config(h, n) & HPET_TN_INT_ROUTE_CAP_MASK) \
    1.60          >> HPET_TN_INT_ROUTE_CAP_SHIFT)
    1.61  
    1.62 -#define hpet_time_after(a, b)   ((int32_t)(b) -(int32_t)(a) < 0)
    1.63 -#define hpet_time_after64(a, b)   ((int64_t)(b) -(int64_t)(a) < 0)
    1.64 +#define hpet_time_after(a, b)   ((int32_t)(b) - (int32_t)(a) < 0)
    1.65 +#define hpet_time_after64(a, b) ((int64_t)(b) - (int64_t)(a) < 0)
    1.66  
    1.67 -static inline uint32_t hpet_read32(HPETState *h, unsigned long addr)
    1.68 +static inline uint64_t hpet_read64(HPETState *h, unsigned long addr)
    1.69  {
    1.70 -    unsigned long p = ((unsigned long)&h->hpet) + addr;
    1.71 -    return  *((uint32_t*)p);
    1.72 -}
    1.73 -
    1.74 -static inline void hpet_write32(HPETState *h, unsigned long addr, uint32_t val)
    1.75 -{
    1.76 -    unsigned long p = ((unsigned long)&h->hpet) + addr;
    1.77 -    *((uint32_t*)p) = val;
    1.78 +    uint64_t *p = (uint64_t *)(((unsigned long)&h->hpet) + addr);
    1.79 +    return (addr >= HPET_T3_CFG) ? 0 : *p;
    1.80  }
    1.81  
    1.82  static int hpet_check_access_length(unsigned long addr, unsigned long len)
    1.83  {
    1.84 -    if ( (len != 4) && (len != 8) )
    1.85 +    if ( (addr & (len - 1)) || (len > 8) )
    1.86      {
    1.87 -        gdprintk(XENLOG_ERR, "HPET: access with len=%lu\n", len);
    1.88 -        goto fail;
    1.89 -    }
    1.90 -
    1.91 -    if ( addr & (len-1) )
    1.92 -    {
    1.93 -        gdprintk(XENLOG_ERR, "HPET: access across register boundary\n");
    1.94 -        goto fail;
    1.95 +        gdprintk(XENLOG_ERR, "HPET: access across register boundary: "
    1.96 +                 "%lx %lx\n", addr, len);
    1.97 +        domain_crash(current->domain);
    1.98 +        return -EINVAL;
    1.99      }
   1.100  
   1.101      return 0;
   1.102 -
   1.103 - fail:
   1.104 -    domain_crash(current->domain);
   1.105 -    return -EINVAL;
   1.106 -}
   1.107 -
   1.108 -static int hpet_check_access_offset(unsigned long addr)
   1.109 -{
   1.110 -    if ( addr >= HPET_T3_CFG )
   1.111 -    {
   1.112 -        gdprintk(XENLOG_ERR, "HPET: only 3 timers supported now\n");
   1.113 -        goto fail;
   1.114 -    }
   1.115 -
   1.116 -    if ( (addr == HPET_T0_ROUTE) || (addr == HPET_T0_ROUTE+4) ||
   1.117 -         (addr == HPET_T1_ROUTE) || (addr == HPET_T1_ROUTE+4) ||
   1.118 -         (addr == HPET_T2_ROUTE) || (addr == HPET_T2_ROUTE+4) )
   1.119 -    {
   1.120 -        gdprintk(XENLOG_ERR, "HPET: FSB interrupt route not supported now\n");
   1.121 -        goto fail;
   1.122 -    }
   1.123 -
   1.124 -    return 0;
   1.125 -
   1.126 - fail:
   1.127 -    domain_crash(current->domain);
   1.128 -    return -EINVAL;
   1.129 -}
   1.130 -
   1.131 -static void hpet_level_triggered_interrupt_not_supported(void)
   1.132 -{
   1.133 -    /* It's hard to support level triggered interrupt in HPET. */
   1.134 -    /* Now we haven't found any OS uses this kind of interrupt of HPET. */
   1.135 -    gdprintk(XENLOG_ERR,
   1.136 -             "HPET: level triggered interrupt not supported now\n");
   1.137 -    domain_crash(current->domain);
   1.138  }
   1.139  
   1.140  static uint64_t hpet_update_maincounter(HPETState *h)
   1.141 @@ -177,104 +116,68 @@ static unsigned long hpet_read(
   1.142      struct vcpu *v, unsigned long addr, unsigned long length)
   1.143  {
   1.144      HPETState *h = &v->domain->arch.hvm_domain.pl_time.vhpet;
   1.145 -    uint64_t mc, result;
   1.146 +    unsigned long result;
   1.147 +    uint64_t val;
   1.148  
   1.149      addr &= HPET_MMAP_SIZE-1;
   1.150  
   1.151      if ( hpet_check_access_length(addr, length) != 0 )
   1.152 -        goto fail;
   1.153 -
   1.154 -    if ( length == 8 )
   1.155 -    {
   1.156 -        /* TODO: no OS is found to use length=8 now. 
   1.157 -         * Windows 2000/XP/2003 doesn't use HPET; all of Linux 
   1.158 -         * and 32bit/64bit Vista use 4-byte-length access.
   1.159 -         * Besides, section 2.4.7 of HPET spec gives a note saying
   1.160 -         * 64bit read may be inaccurate in some platforms. */
   1.161 -        gdprintk(XENLOG_ERR, "HPET: hpet_read with len=8 not implementated\n");
   1.162 -        domain_crash(v->domain);
   1.163 -        goto fail;
   1.164 -    }
   1.165 +        return ~0UL;
   1.166  
   1.167 -    switch ( addr )
   1.168 -    {
   1.169 -    case HPET_COUNTER:
   1.170 -        mc = hpet_update_maincounter(h);
   1.171 -        result = mc & 0xffffffffU;
   1.172 -        break;
   1.173 -    case HPET_COUNTER + 4:
   1.174 -        mc = hpet_update_maincounter(h);
   1.175 -        result = (mc >> 32);
   1.176 -        break;
   1.177 -    case HPET_T0_CMP:
   1.178 -        result = hpet_read32(h, addr);
   1.179 -        break;
   1.180 -    case HPET_T0_CMP + 4:
   1.181 -        result = timer_is_32bit(h, 0) ? 0 : hpet_read32(h, addr);
   1.182 -        break;
   1.183 -    default:
   1.184 -        if ( hpet_check_access_offset(addr) != 0 )
   1.185 -            goto fail;
   1.186 -        result = hpet_read32(h, addr);
   1.187 -        break;
   1.188 -    }
   1.189 +    val = hpet_read64(h, addr & ~7);
   1.190 +    if ( (addr & ~7) == HPET_COUNTER )
   1.191 +        val = hpet_update_maincounter(h);
   1.192 +
   1.193 +    result = val;
   1.194 +    if ( length != 8 )
   1.195 +        result = (val >> ((addr & 7) * 8)) & ((1UL << (length * 8)) - 1);
   1.196  
   1.197      return result;
   1.198 -
   1.199 - fail:
   1.200 -    return ~0UL;
   1.201  }
   1.202  
   1.203  static void hpet_stop_timer(HPETState *h, unsigned int tn)
   1.204  {
   1.205 -    ASSERT( tn < HPET_TIMER_NUM );
   1.206 +    ASSERT(tn < HPET_TIMER_NUM);
   1.207      stop_timer(&h->timers[tn]);
   1.208  }
   1.209  
   1.210  static void hpet_set_timer(HPETState *h, unsigned int tn)
   1.211  {
   1.212 -    uint64_t tn_cmp;
   1.213 -    uint32_t cur_tick;
   1.214 +    uint64_t tn_cmp, cur_tick;
   1.215  
   1.216      ASSERT(tn < HPET_TIMER_NUM);
   1.217      
   1.218      if ( !hpet_enabled(h) || !timer_enabled(h, tn) )
   1.219          return;
   1.220  
   1.221 -    switch ( tn )
   1.222 +    if ( (tn == 0) && (h->hpet.config & HPET_CFG_LEGACY) )
   1.223      {
   1.224 -    case 0:
   1.225 -        if ( !(h->hpet.config & HPET_CFG_LEGACY) )
   1.226 -        {
   1.227 -            gdprintk(XENLOG_INFO,
   1.228 -                     "HPET: LegacyReplacementRoute not set for timer0\n");
   1.229 -        }
   1.230 -        else
   1.231 -        {
   1.232 -            /* HPET specification requires PIT shouldn't generate
   1.233 -             * interrupts if LegacyReplacementRoute is set for timer0 */
   1.234 -            PITState *pit = &h->vcpu->domain->arch.hvm_domain.pl_time.vpit;
   1.235 -            pit_stop_channel0_irq(pit);
   1.236 -        }
   1.237 -        if ( timer_is_32bit(h, 0) )
   1.238 -            h->t0_period = hpet_tick_to_ns(h, (uint32_t)h->t0_initial_cnt);
   1.239 -        else
   1.240 -            h->t0_period = hpet_tick_to_ns(h, h->t0_initial_cnt);
   1.241 -        h->t0_period = hpet_tick_to_ns(h, h->t0_initial_cnt);
   1.242 -        set_timer(&h->timers[0], NOW() + h->t0_period);
   1.243 -        break;
   1.244 -    case 1:
   1.245 -    case 2: /* only support 32bit timer1 & timer 2 now */
   1.246 -        tn_cmp = h->hpet.timers[tn].c64 & 0xffffffffULL;
   1.247 -        cur_tick = hpet_update_maincounter(h);
   1.248 -        if ( tn_cmp > cur_tick )
   1.249 -            set_timer(&h->timers[tn], NOW() +
   1.250 -                      hpet_tick_to_ns(h, tn_cmp-cur_tick));
   1.251 -        else /* handle the overflow case */
   1.252 -            set_timer(&h->timers[tn], NOW() +
   1.253 -                      hpet_tick_to_ns(h, 0xffffffff-cur_tick+tn_cmp));
   1.254 -        break;
   1.255 +        /* HPET specification requires PIT shouldn't generate
   1.256 +         * interrupts if LegacyReplacementRoute is set for timer0 */
   1.257 +        PITState *pit = &h->vcpu->domain->arch.hvm_domain.pl_time.vpit;
   1.258 +        pit_stop_channel0_irq(pit);
   1.259      }
   1.260 +
   1.261 +    tn_cmp   = h->hpet.timers[tn].cmp;
   1.262 +    cur_tick = hpet_update_maincounter(h);
   1.263 +    if ( timer_is_32bit(h, tn) )
   1.264 +    {
   1.265 +        tn_cmp   = (uint32_t)tn_cmp;
   1.266 +        cur_tick = (uint32_t)cur_tick;
   1.267 +    }
   1.268 +
   1.269 +    if ( (int64_t)(tn_cmp - cur_tick) > 0 )
   1.270 +        set_timer(&h->timers[tn], NOW() +
   1.271 +                  hpet_tick_to_ns(h, tn_cmp-cur_tick));
   1.272 +    else
   1.273 +        set_timer(&h->timers[tn], NOW());
   1.274 +}
   1.275 +
   1.276 +static uint64_t hpet_fixup_reg(uint64_t new, uint64_t old, uint64_t mask)
   1.277 +{
   1.278 +    new &= mask;
   1.279 +    new |= old & ~mask;
   1.280 +    return new;
   1.281  }
   1.282  
   1.283  static void hpet_write(
   1.284 @@ -282,7 +185,7 @@ static void hpet_write(
   1.285      unsigned long length, unsigned long val)
   1.286  {
   1.287      HPETState *h = &v->domain->arch.hvm_domain.pl_time.vhpet;
   1.288 -    unsigned long old_val;
   1.289 +    uint64_t old_val, new_val;
   1.290      int tn, i;
   1.291  
   1.292      addr &= HPET_MMAP_SIZE-1;
   1.293 @@ -290,106 +193,93 @@ static void hpet_write(
   1.294      if ( hpet_check_access_length(addr, length) != 0 )
   1.295          return;
   1.296  
   1.297 -    if ( length == 8 )
   1.298 -    {
   1.299 -        gdprintk(XENLOG_ERR, "HPET: hpet_write with len=8 not implemented\n");
   1.300 -        domain_crash(v->domain);
   1.301 -        return;
   1.302 -    }
   1.303 +    old_val = hpet_read64(h, addr & ~7);
   1.304 +    if ( (addr & ~7) == HPET_COUNTER )
   1.305 +        old_val = hpet_update_maincounter(h);
   1.306  
   1.307 -    switch ( addr )
   1.308 +    new_val = val;
   1.309 +    if ( length != 8 )
   1.310 +        new_val = hpet_fixup_reg(
   1.311 +            new_val << (addr & 7) * 8, old_val,
   1.312 +            ((1ULL << (length*8)) - 1) << ((addr & 7) * 8));
   1.313 +
   1.314 +    switch ( addr & ~7 )
   1.315      {
   1.316 -    case HPET_ID: 
   1.317 -    case HPET_ID + 4: 
   1.318 -        gdprintk(XENLOG_WARNING,
   1.319 -                 "HPET: Capabilities and ID register is readonly\n");
   1.320 -        break;
   1.321 -    case HPET_CFG: 
   1.322 -        old_val = h->hpet.config;
   1.323 -        h->hpet.config = val;
   1.324 +    case HPET_CFG:
   1.325 +        h->hpet.config = hpet_fixup_reg(new_val, old_val, 0x3);
   1.326  
   1.327 -        if ( !(old_val & HPET_CFG_ENABLE) && (val & HPET_CFG_ENABLE) )
   1.328 +        if ( !(old_val & HPET_CFG_ENABLE) && (new_val & HPET_CFG_ENABLE) )
   1.329          {
   1.330 -            /* enable main counter & interrupt generating */
   1.331 +            /* Enable main counter and interrupt generation. */
   1.332              h->mc_offset = h->hpet.mc64 - hvm_get_guest_time(h->vcpu);
   1.333              for ( i = 0; i < HPET_TIMER_NUM; i++ )
   1.334                  hpet_set_timer(h, i); 
   1.335          }
   1.336 -        else if ( (old_val & HPET_CFG_ENABLE) && !(val & HPET_CFG_ENABLE) )
   1.337 +        else if ( (old_val & HPET_CFG_ENABLE) && !(new_val & HPET_CFG_ENABLE) )
   1.338          {
   1.339 -            /* halt main counter & disable interrupt generating */
   1.340 +            /* Halt main counter and disable interrupt generation. */
   1.341              h->hpet.mc64 = h->mc_offset + hvm_get_guest_time(h->vcpu);
   1.342              for ( i = 0; i < HPET_TIMER_NUM; i++ )
   1.343                  hpet_stop_timer(h, i);
   1.344          }
   1.345          break;
   1.346 -    case HPET_STATUS:
   1.347 -        hpet_level_triggered_interrupt_not_supported();
   1.348 -        break;
   1.349 +
   1.350      case HPET_COUNTER:
   1.351 -    case HPET_COUNTER + 4:
   1.352          if ( hpet_enabled(h) )
   1.353              gdprintk(XENLOG_WARNING, 
   1.354                       "HPET: writing main counter but it's not halted!\n");
   1.355 -        hpet_write32(h, addr, val);
   1.356 +        h->hpet.mc64 = new_val;
   1.357          break;
   1.358 -    default:
   1.359 -        if ( hpet_check_access_offset(addr) != 0 )
   1.360 -            break;
   1.361  
   1.362 -        if ( (addr < HPET_T0_CFG) || (addr >= HPET_T2_ROUTE) )
   1.363 +    case HPET_T0_CFG:
   1.364 +    case HPET_T1_CFG:
   1.365 +    case HPET_T2_CFG:
   1.366 +        tn = (addr - HPET_T0_CFG) >> 5;
   1.367 +
   1.368 +        h->hpet.timers[tn].config = hpet_fixup_reg(new_val, old_val, 0x3f4e);
   1.369 +
   1.370 +        if ( timer_level(h, tn) )
   1.371          {
   1.372 -            gdprintk(XENLOG_WARNING,
   1.373 -                     "HPET: writing reserved addr=0x%lx, ignored\n", addr);
   1.374 +            gdprintk(XENLOG_ERR,
   1.375 +                     "HPET: level triggered interrupt not supported now\n");
   1.376 +            domain_crash(current->domain);
   1.377              break;
   1.378          }
   1.379  
   1.380 -        tn = (addr - HPET_T0_CFG) / 0x20;
   1.381 -        if ( (addr == HPET_T0_CMP + 0x20*tn) || 
   1.382 -             (addr == HPET_T0_CMP + 0x20*tn+4) )
   1.383 -        {
   1.384 -            hpet_write32(h, addr, val);
   1.385 -            if ( addr == HPET_T0_CMP )
   1.386 -                *((uint32_t*)&(h->t0_initial_cnt)) = val;
   1.387 -            else if ( addr == HPET_T0_CMP + 4 )
   1.388 -                *(((uint32_t*)&(h->t0_initial_cnt))+1) = val;
   1.389 -            if( hpet_enabled(h) && timer_enabled(h, tn) )
   1.390 -                hpet_set_timer(h, tn);
   1.391 -        }
   1.392 -        else /* HPET_Tn_CFG or HPET_Tn_CFG+4 */
   1.393 -        {
   1.394 -            if ( addr == (HPET_T0_CFG + 0x20*tn + 4) )
   1.395 -            {
   1.396 -                gdprintk(XENLOG_WARNING,
   1.397 -                         "HPET:  Timer%d_CFG[63..32] is readonly\n", tn);
   1.398 -            }
   1.399 -            else
   1.400 -            {
   1.401 -                old_val = timer_config(h, tn);
   1.402 -                if( (old_val & HPET_TN_CFG_BITS_READONLY_OR_RESERVED) !=
   1.403 -                    (val & HPET_TN_CFG_BITS_READONLY_OR_RESERVED) )
   1.404 -                {
   1.405 -                    gdprintk(XENLOG_ERR,
   1.406 -                             "HPET: TN_CFG writing incorrect value\n");
   1.407 -                    domain_crash(v->domain);
   1.408 -                    break;
   1.409 -                }
   1.410 -                hpet_write32(h, addr, val);
   1.411 +        if ( new_val & HPET_TN_32BIT )
   1.412 +            h->hpet.timers[tn].cmp = (uint32_t)h->hpet.timers[tn].cmp;
   1.413  
   1.414 -                if ( timer_level(h, tn) )
   1.415 -                {
   1.416 -                    hpet_level_triggered_interrupt_not_supported();
   1.417 -                    break;
   1.418 -                }
   1.419 +        if ( !(old_val & HPET_TN_ENABLE) && (new_val & HPET_TN_ENABLE) )
   1.420 +            hpet_set_timer(h, tn);
   1.421 +        else if ( (old_val & HPET_TN_ENABLE) && !(new_val & HPET_TN_ENABLE) )
   1.422 +            hpet_stop_timer(h, tn);
   1.423 +        break;
   1.424  
   1.425 -                if ( !(old_val & HPET_TN_ENABLE) &&
   1.426 -                     (val & HPET_TN_ENABLE) )
   1.427 -                    hpet_set_timer(h, tn);
   1.428 -                else if ( (old_val & HPET_TN_ENABLE) &&
   1.429 -                          !(val & HPET_TN_ENABLE) )
   1.430 -                    hpet_stop_timer(h, tn); 
   1.431 -            }
   1.432 -        }
   1.433 +    case HPET_T0_CMP:
   1.434 +    case HPET_T1_CMP:
   1.435 +    case HPET_T2_CMP:
   1.436 +        tn = (addr - HPET_T0_CMP) >> 5;
   1.437 +        if ( timer_is_32bit(h, tn) )
   1.438 +            new_val = (uint32_t)new_val;
   1.439 +        if ( !timer_is_periodic(h, tn) ||
   1.440 +             (h->hpet.timers[tn].config & HPET_TN_SETVAL) )
   1.441 +            h->hpet.timers[tn].cmp = new_val;
   1.442 +        else
   1.443 +            h->period[tn] = new_val;
   1.444 +        h->hpet.timers[tn].config &= ~HPET_TN_SETVAL;
   1.445 +        if ( hpet_enabled(h) && timer_enabled(h, tn) )
   1.446 +            hpet_set_timer(h, tn);
   1.447 +        break;
   1.448 +
   1.449 +    case HPET_T0_ROUTE:
   1.450 +    case HPET_T1_ROUTE:
   1.451 +    case HPET_T2_ROUTE:
   1.452 +        tn = (addr - HPET_T0_ROUTE) >> 5;
   1.453 +        h->hpet.timers[tn].hpet_fsb[0] = new_val;
   1.454 +        break;
   1.455 +
   1.456 +    default:
   1.457 +        /* Ignore writes to unsupported and reserved registers. */
   1.458          break;
   1.459      }
   1.460  }
   1.461 @@ -402,26 +292,27 @@ static int hpet_range(struct vcpu *v, un
   1.462  
   1.463  struct hvm_mmio_handler hpet_mmio_handler = {
   1.464      .check_handler = hpet_range,
   1.465 -    .read_handler = hpet_read,
   1.466 +    .read_handler  = hpet_read,
   1.467      .write_handler = hpet_write
   1.468  };
   1.469  
   1.470 -static void hpet_set_irq(struct domain *d, int hpet_tn)
   1.471 -{
   1.472 -    /* if LegacyReplacementRoute bit is set, HPET specification requires
   1.473 -       timer0 be routed to IRQ0 in NON-APIC or IRQ2 in the I/O APIC,
   1.474 -       timer1 be routed to IRQ8 in NON-APIC or IRQ8 in the I/O APIC. */
   1.475 -    int isa_irq = (hpet_tn == 0) ? 0 : 8;
   1.476 -    hvm_isa_irq_deassert(d, isa_irq);
   1.477 -    hvm_isa_irq_assert(d, isa_irq);
   1.478 -}
   1.479 -
   1.480  static void hpet_route_interrupt(HPETState *h, unsigned int tn)
   1.481  {
   1.482      unsigned int tn_int_route = timer_int_route(h, tn);
   1.483      struct domain *d = h->vcpu->domain;
   1.484      struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
   1.485  
   1.486 +    if ( (tn <= 1) && (h->hpet.config & HPET_CFG_LEGACY) )
   1.487 +    {
   1.488 +        /* if LegacyReplacementRoute bit is set, HPET specification requires
   1.489 +           timer0 be routed to IRQ0 in NON-APIC or IRQ2 in the I/O APIC,
   1.490 +           timer1 be routed to IRQ8 in NON-APIC or IRQ8 in the I/O APIC. */
   1.491 +        int isa_irq = (tn == 0) ? 0 : 8;
   1.492 +        hvm_isa_irq_deassert(d, isa_irq);
   1.493 +        hvm_isa_irq_assert(d, isa_irq);
   1.494 +        return;
   1.495 +    }
   1.496 +
   1.497      if ( !(timer_int_route_cap(h, tn) & (1U << tn_int_route)) )
   1.498      {
   1.499          gdprintk(XENLOG_ERR,
   1.500 @@ -444,45 +335,24 @@ static void hpet_timer_fn(void *opaque)
   1.501  
   1.502      if ( !hpet_enabled(h) || !timer_enabled(h, tn) )
   1.503          return;
   1.504 -    
   1.505 -    if ( timer_level(h, tn) )
   1.506 -    {
   1.507 -        hpet_level_triggered_interrupt_not_supported();
   1.508 -        return;
   1.509 -    }
   1.510 -
   1.511 -    switch ( tn )
   1.512 -    {
   1.513 -        case 0:
   1.514 -        case 1:
   1.515 -            if ( h->hpet.config & HPET_CFG_LEGACY )
   1.516 -                hpet_set_irq(h->vcpu->domain, tn);
   1.517 -            else
   1.518 -                hpet_route_interrupt(h, tn);
   1.519  
   1.520 -            if ( (tn == 0) && timer_is_periodic(h, tn) )
   1.521 -            {
   1.522 -                uint64_t mc = hpet_update_maincounter(h);
   1.523 -                if ( timer_is_32bit(h, 0) )
   1.524 -                {
   1.525 -                    while ( hpet_time_after(mc, h->hpet.timers[0].c32) )
   1.526 -                        h->hpet.timers[0].c32 += h->t0_initial_cnt;
   1.527 -                }
   1.528 -                else
   1.529 -                {
   1.530 -                    while ( hpet_time_after64(mc, h->hpet.timers[0].c64) )
   1.531 -                        h->hpet.timers[0].c64 += h->t0_initial_cnt;
   1.532 -                }
   1.533 -                set_timer(&h->timers[tn], NOW() + h->t0_period);
   1.534 -            }
   1.535 -            break;
   1.536 -        case 2:
   1.537 -            hpet_route_interrupt(h, tn);
   1.538 -            break;
   1.539 -        default:
   1.540 -            gdprintk(XENLOG_WARNING,
   1.541 -                     "HPET: timer%u is not supported now\n", tn);
   1.542 -            break;
   1.543 +    hpet_route_interrupt(h, tn);
   1.544 +
   1.545 +    if ( timer_is_periodic(h, tn) && (h->period[tn] != 0) )
   1.546 +    {
   1.547 +        uint64_t mc = hpet_update_maincounter(h);
   1.548 +        if ( timer_is_32bit(h, tn) )
   1.549 +        {
   1.550 +            while ( hpet_time_after(mc, h->hpet.timers[tn].cmp) )
   1.551 +                h->hpet.timers[tn].cmp = (uint32_t)(
   1.552 +                    h->hpet.timers[tn].cmp + h->period[tn]);
   1.553 +        }
   1.554 +        else
   1.555 +        {
   1.556 +            while ( hpet_time_after64(mc, h->hpet.timers[tn].cmp) )
   1.557 +                h->hpet.timers[tn].cmp += h->period[tn];
   1.558 +        }
   1.559 +        set_timer(&h->timers[tn], NOW() + hpet_tick_to_ns(h, h->period[tn]));
   1.560      }
   1.561  
   1.562      vcpu_kick(h->vcpu);    
   1.563 @@ -506,23 +376,19 @@ void hpet_init(struct vcpu *v)
   1.564  
   1.565      h->vcpu = v;
   1.566      h->tsc_freq = ticks_per_sec(v);
   1.567 -    h->hpet.capability = HPET_CAP_ID_REG;
   1.568 +
   1.569 +    /* 64-bit main counter; 3 timers supported; LegacyReplacementRoute. */
   1.570 +    h->hpet.capability = 0x8086A201ULL;
   1.571  
   1.572      /* This is the number of femptoseconds per HPET tick. */
   1.573 -    /* Here we define HPET's frequency as tsc's. */
   1.574 +    /* Here we define HPET's frequency to be the same as the TSC's. */
   1.575      h->hpet.capability |= ((S_TO_FS/h->tsc_freq) << 32);
   1.576  
   1.577 -    h->hpet.timers[0].config = HPET_TN_INT_ROUTE_CAP | 
   1.578 -                        HPET_TN_SIZE_CAP | HPET_TN_PERIODIC_CAP;
   1.579 -    h->hpet.timers[0].c64 = HPET_TIMER_CMP64_DEFAULT;
   1.580 -
   1.581 -    h->hpet.timers[1].config = HPET_TN_INT_ROUTE_CAP;
   1.582 -    h->hpet.timers[1].c32 = HPET_TIMER_CMP32_DEFAULT;
   1.583 -    h->hpet.timers[2].config = HPET_TN_INT_ROUTE_CAP;
   1.584 -    h->hpet.timers[2].c32 = HPET_TIMER_CMP32_DEFAULT;
   1.585 -
   1.586      for ( i = 0; i < HPET_TIMER_NUM; i++ )
   1.587      {
   1.588 +        h->hpet.timers[i].config = 
   1.589 +            HPET_TN_INT_ROUTE_CAP | HPET_TN_SIZE_CAP | HPET_TN_PERIODIC_CAP;
   1.590 +        h->hpet.timers[i].cmp = ~0ULL;
   1.591          h->timer_fn_info[i].hs = h;
   1.592          h->timer_fn_info[i].tn = i;
   1.593          init_timer(&h->timers[i], hpet_timer_fn, &h->timer_fn_info[i],
     2.1 --- a/xen/include/asm-x86/hvm/vpt.h	Fri Dec 29 13:02:19 2006 +0000
     2.2 +++ b/xen/include/asm-x86/hvm/vpt.h	Fri Dec 29 14:12:55 2006 +0000
     2.3 @@ -39,17 +39,11 @@ struct HPET {
     2.4      uint64_t res1;              /* reserved */
     2.5      uint64_t isr;               /* interrupt status reg */
     2.6      uint64_t res2[25];          /* reserved */
     2.7 -    union {                     /* main counter */
     2.8 -        uint64_t mc64;
     2.9 -        uint32_t mc32;
    2.10 -    };
    2.11 +    uint64_t mc64;              /* main counter */
    2.12      uint64_t res3;              /* reserved */
    2.13      struct {                    /* timers */
    2.14          uint64_t config;        /* configuration/cap */
    2.15 -        union {                 /* timer compare register */
    2.16 -            uint64_t c64;
    2.17 -            uint32_t c32;
    2.18 -        };
    2.19 +        uint64_t cmp;           /* comparator */
    2.20          uint64_t hpet_fsb[2];   /* FSB route, not supported now */
    2.21      } timers[HPET_TIMER_NUM];
    2.22  };
    2.23 @@ -65,8 +59,7 @@ typedef struct HPETState {
    2.24      struct vcpu     *vcpu;
    2.25      uint64_t        tsc_freq;
    2.26      uint64_t        mc_offset;
    2.27 -    uint64_t        t0_initial_cnt;
    2.28 -    uint64_t        t0_period;
    2.29 +    uint64_t        period[HPET_TIMER_NUM];
    2.30      struct timer timers[HPET_TIMER_NUM];
    2.31      struct HPET_timer_fn_info timer_fn_info[HPET_TIMER_NUM]; 
    2.32  } HPETState;