[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] [HVM] Fix HPET timer to support 8-byte accesses, erroneous updates
# 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
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |