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>
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 + /* HPET specification requires PIT shouldn't generate 1.225 + * interrupts if LegacyReplacementRoute is set for timer0 */ 1.226 + PITState *pit = &h->vcpu->domain->arch.hvm_domain.pl_time.vpit; 1.227 + pit_stop_channel0_irq(pit); 1.228 + } 1.229 + 1.230 + tn_cmp = h->hpet.timers[tn].cmp; 1.231 + cur_tick = hpet_update_maincounter(h); 1.232 + if ( timer_is_32bit(h, tn) ) 1.233 { 1.234 - case 0: 1.235 - if ( !(h->hpet.config & HPET_CFG_LEGACY) ) 1.236 - { 1.237 - gdprintk(XENLOG_INFO, 1.238 - "HPET: LegacyReplacementRoute not set for timer0\n"); 1.239 - } 1.240 - else 1.241 - { 1.242 - /* HPET specification requires PIT shouldn't generate 1.243 - * interrupts if LegacyReplacementRoute is set for timer0 */ 1.244 - PITState *pit = &h->vcpu->domain->arch.hvm_domain.pl_time.vpit; 1.245 - pit_stop_channel0_irq(pit); 1.246 - } 1.247 - if ( timer_is_32bit(h, 0) ) 1.248 - h->t0_period = hpet_tick_to_ns(h, (uint32_t)h->t0_initial_cnt); 1.249 - else 1.250 - h->t0_period = hpet_tick_to_ns(h, h->t0_initial_cnt); 1.251 - h->t0_period = hpet_tick_to_ns(h, h->t0_initial_cnt); 1.252 - set_timer(&h->timers[0], NOW() + h->t0_period); 1.253 - break; 1.254 - case 1: 1.255 - case 2: /* only support 32bit timer1 & timer 2 now */ 1.256 - tn_cmp = h->hpet.timers[tn].c64 & 0xffffffffULL; 1.257 - cur_tick = hpet_update_maincounter(h); 1.258 - if ( tn_cmp > cur_tick ) 1.259 - set_timer(&h->timers[tn], NOW() + 1.260 - hpet_tick_to_ns(h, tn_cmp-cur_tick)); 1.261 - else /* handle the overflow case */ 1.262 - set_timer(&h->timers[tn], NOW() + 1.263 - hpet_tick_to_ns(h, 0xffffffff-cur_tick+tn_cmp)); 1.264 - break; 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 + case HPET_T0_CFG: 1.363 + case HPET_T1_CFG: 1.364 + case HPET_T2_CFG: 1.365 + tn = (addr - HPET_T0_CFG) >> 5; 1.366 1.367 - if ( (addr < HPET_T0_CFG) || (addr >= HPET_T2_ROUTE) ) 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 ( !(old_val & HPET_TN_ENABLE) && (new_val & HPET_TN_ENABLE) ) 1.415 + hpet_set_timer(h, tn); 1.416 + else if ( (old_val & HPET_TN_ENABLE) && !(new_val & HPET_TN_ENABLE) ) 1.417 + hpet_stop_timer(h, tn); 1.418 + break; 1.419 1.420 - if ( timer_level(h, tn) ) 1.421 - { 1.422 - hpet_level_triggered_interrupt_not_supported(); 1.423 - break; 1.424 - } 1.425 + case HPET_T0_CMP: 1.426 + case HPET_T1_CMP: 1.427 + case HPET_T2_CMP: 1.428 + tn = (addr - HPET_T0_CMP) >> 5; 1.429 + if ( timer_is_32bit(h, tn) ) 1.430 + new_val = (uint32_t)new_val; 1.431 + if ( !timer_is_periodic(h, tn) || 1.432 + (h->hpet.timers[tn].config & HPET_TN_SETVAL) ) 1.433 + h->hpet.timers[tn].cmp = new_val; 1.434 + else 1.435 + h->period[tn] = new_val; 1.436 + h->hpet.timers[tn].config &= ~HPET_TN_SETVAL; 1.437 + if ( hpet_enabled(h) && timer_enabled(h, tn) ) 1.438 + hpet_set_timer(h, tn); 1.439 + break; 1.440 1.441 - if ( !(old_val & HPET_TN_ENABLE) && 1.442 - (val & HPET_TN_ENABLE) ) 1.443 - hpet_set_timer(h, tn); 1.444 - else if ( (old_val & HPET_TN_ENABLE) && 1.445 - !(val & HPET_TN_ENABLE) ) 1.446 - hpet_stop_timer(h, tn); 1.447 - } 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 + hpet_route_interrupt(h, tn); 1.520 1.521 - if ( (tn == 0) && timer_is_periodic(h, tn) ) 1.522 - { 1.523 - uint64_t mc = hpet_update_maincounter(h); 1.524 - if ( timer_is_32bit(h, 0) ) 1.525 - { 1.526 - while ( hpet_time_after(mc, h->hpet.timers[0].c32) ) 1.527 - h->hpet.timers[0].c32 += h->t0_initial_cnt; 1.528 - } 1.529 - else 1.530 - { 1.531 - while ( hpet_time_after64(mc, h->hpet.timers[0].c64) ) 1.532 - h->hpet.timers[0].c64 += h->t0_initial_cnt; 1.533 - } 1.534 - set_timer(&h->timers[tn], NOW() + h->t0_period); 1.535 - } 1.536 - break; 1.537 - case 2: 1.538 - hpet_route_interrupt(h, tn); 1.539 - break; 1.540 - default: 1.541 - gdprintk(XENLOG_WARNING, 1.542 - "HPET: timer%u is not supported now\n", tn); 1.543 - break; 1.544 + if ( timer_is_periodic(h, tn) && (h->period[tn] != 0) ) 1.545 + { 1.546 + uint64_t mc = hpet_update_maincounter(h); 1.547 + if ( timer_is_32bit(h, tn) ) 1.548 + { 1.549 + while ( hpet_time_after(mc, h->hpet.timers[tn].cmp) ) 1.550 + h->hpet.timers[tn].cmp = (uint32_t)( 1.551 + h->hpet.timers[tn].cmp + h->period[tn]); 1.552 + } 1.553 + else 1.554 + { 1.555 + while ( hpet_time_after64(mc, h->hpet.timers[tn].cmp) ) 1.556 + h->hpet.timers[tn].cmp += h->period[tn]; 1.557 + } 1.558 + set_timer(&h->timers[tn], NOW() + hpet_tick_to_ns(h, h->period[tn])); 1.559 } 1.560 1.561 vcpu_kick(h->vcpu); 1.562 @@ -506,23 +376,19 @@ void hpet_init(struct vcpu *v) 1.563 1.564 h->vcpu = v; 1.565 h->tsc_freq = ticks_per_sec(v); 1.566 - h->hpet.capability = HPET_CAP_ID_REG; 1.567 + 1.568 + /* 64-bit main counter; 3 timers supported; LegacyReplacementRoute. */ 1.569 + h->hpet.capability = 0x8086A201ULL; 1.570 1.571 /* This is the number of femptoseconds per HPET tick. */ 1.572 - /* Here we define HPET's frequency as tsc's. */ 1.573 + /* Here we define HPET's frequency to be the same as the TSC's. */ 1.574 h->hpet.capability |= ((S_TO_FS/h->tsc_freq) << 32); 1.575 1.576 - h->hpet.timers[0].config = HPET_TN_INT_ROUTE_CAP | 1.577 - HPET_TN_SIZE_CAP | HPET_TN_PERIODIC_CAP; 1.578 - h->hpet.timers[0].c64 = HPET_TIMER_CMP64_DEFAULT; 1.579 - 1.580 - h->hpet.timers[1].config = HPET_TN_INT_ROUTE_CAP; 1.581 - h->hpet.timers[1].c32 = HPET_TIMER_CMP32_DEFAULT; 1.582 - h->hpet.timers[2].config = HPET_TN_INT_ROUTE_CAP; 1.583 - h->hpet.timers[2].c32 = HPET_TIMER_CMP32_DEFAULT; 1.584 - 1.585 for ( i = 0; i < HPET_TIMER_NUM; i++ ) 1.586 { 1.587 + h->hpet.timers[i].config = 1.588 + HPET_TN_INT_ROUTE_CAP | HPET_TN_SIZE_CAP | HPET_TN_PERIODIC_CAP; 1.589 + h->hpet.timers[i].cmp = ~0ULL; 1.590 h->timer_fn_info[i].hs = h; 1.591 h->timer_fn_info[i].tn = i; 1.592 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;