hpet.c
来自「xen虚拟机源代码安装包」· C语言 代码 · 共 599 行 · 第 1/2 页
C
599 行
/* * hpet.c: HPET emulation for HVM guests. * Copyright (c) 2006, Intel Corporation. * Copyright (c) 2006, Keir Fraser <keir@xensource.com> * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 59 Temple * Place - Suite 330, Boston, MA 02111-1307 USA. */#include <asm/hvm/vpt.h>#include <asm/hvm/io.h>#include <asm/hvm/support.h>#include <asm/current.h>#include <xen/sched.h>#include <xen/event.h>#define HPET_BASE_ADDRESS 0xfed00000ULL#define HPET_MMAP_SIZE 1024#define S_TO_NS 1000000000ULL /* 1s = 10^9 ns */#define S_TO_FS 1000000000000000ULL /* 1s = 10^15 fs *//* Frequency_of_Xen_systeme_time / frequency_of_HPET = 16 */#define STIME_PER_HPET_TICK 16#define guest_time_hpet(v) (hvm_get_guest_time(v) / STIME_PER_HPET_TICK)#define HPET_ID 0x000#define HPET_PERIOD 0x004#define HPET_CFG 0x010#define HPET_STATUS 0x020#define HPET_COUNTER 0x0f0#define HPET_T0_CFG 0x100#define HPET_T0_CMP 0x108#define HPET_T0_ROUTE 0x110#define HPET_T1_CFG 0x120#define HPET_T1_CMP 0x128#define HPET_T1_ROUTE 0x130#define HPET_T2_CFG 0x140#define HPET_T2_CMP 0x148#define HPET_T2_ROUTE 0x150#define HPET_T3_CFG 0x160#define HPET_CFG_ENABLE 0x001#define HPET_CFG_LEGACY 0x002#define HPET_TN_INT_TYPE_LEVEL 0x002#define HPET_TN_ENABLE 0x004#define HPET_TN_PERIODIC 0x008#define HPET_TN_PERIODIC_CAP 0x010#define HPET_TN_SIZE_CAP 0x020#define HPET_TN_SETVAL 0x040#define HPET_TN_32BIT 0x100#define HPET_TN_INT_ROUTE_MASK 0x3e00#define HPET_TN_INT_ROUTE_SHIFT 9#define HPET_TN_INT_ROUTE_CAP_SHIFT 32#define HPET_TN_CFG_BITS_READONLY_OR_RESERVED 0xffff80b1U/* can be routed to IOAPIC.redirect_table[23..20] */#define HPET_TN_INT_ROUTE_CAP (0x00f00000ULL \ << HPET_TN_INT_ROUTE_CAP_SHIFT) #define HPET_TN_INT_ROUTE_CAP_MASK (0xffffffffULL \ << HPET_TN_INT_ROUTE_CAP_SHIFT)#define hpet_tick_to_ns(h, tick) \ ((s_time_t)((((tick) > (h)->hpet_to_ns_limit) ? \ ~0ULL : (tick) * (h)->hpet_to_ns_scale) >> 10))#define timer_config(h, n) (h->hpet.timers[n].config)#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 hpet_enabled(h) (h->hpet.config & HPET_CFG_ENABLE)#define timer_level(h, n) (timer_config(h, n) & HPET_TN_INT_TYPE_LEVEL)#define timer_int_route(h, n) \ ((timer_config(h, n) & HPET_TN_INT_ROUTE_MASK) >> HPET_TN_INT_ROUTE_SHIFT)#define timer_int_route_cap(h, n) \ ((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 uint64_t hpet_read64(HPETState *h, unsigned long addr){ addr &= ~7; switch ( addr ) { case HPET_ID: return h->hpet.capability; case HPET_CFG: return h->hpet.config; case HPET_STATUS: return h->hpet.isr; case HPET_COUNTER: return h->hpet.mc64; case HPET_T0_CFG: case HPET_T1_CFG: case HPET_T2_CFG: return h->hpet.timers[(addr - HPET_T0_CFG) >> 5].config; case HPET_T0_CMP: case HPET_T1_CMP: case HPET_T2_CMP: return h->hpet.timers[(addr - HPET_T0_CMP) >> 5].cmp; case HPET_T0_ROUTE: case HPET_T1_ROUTE: case HPET_T2_ROUTE: return h->hpet.timers[(addr - HPET_T0_ROUTE) >> 5].fsb; } return 0;}static inline int hpet_check_access_length( unsigned long addr, unsigned long len){ if ( (addr & (len - 1)) || (len > 8) ) { /* * According to ICH9 specification, unaligned accesses may result * in unexpected behaviour or master abort, but should not crash/hang. * Hence we read all-ones, drop writes, and log a warning. */ gdprintk(XENLOG_WARNING, "HPET: access across register boundary: " "%lx %lx\n", addr, len); return -EINVAL; } return 0;}static inline uint64_t hpet_read_maincounter(HPETState *h){ ASSERT(spin_is_locked(&h->lock)); if ( hpet_enabled(h) ) return guest_time_hpet(h->vcpu) + h->mc_offset; else return h->hpet.mc64;}static int hpet_read( struct vcpu *v, unsigned long addr, unsigned long length, unsigned long *pval){ HPETState *h = &v->domain->arch.hvm_domain.pl_time.vhpet; unsigned long result; uint64_t val; addr &= HPET_MMAP_SIZE-1; if ( hpet_check_access_length(addr, length) != 0 ) { result = ~0ul; goto out; } spin_lock(&h->lock); val = hpet_read64(h, addr); if ( (addr & ~7) == HPET_COUNTER ) val = hpet_read_maincounter(h); result = val; if ( length != 8 ) result = (val >> ((addr & 7) * 8)) & ((1ULL << (length * 8)) - 1); spin_unlock(&h->lock); out: *pval = result; return X86EMUL_OKAY;}static void hpet_stop_timer(HPETState *h, unsigned int tn){ ASSERT(tn < HPET_TIMER_NUM); ASSERT(spin_is_locked(&h->lock)); stop_timer(&h->timers[tn]);}/* the number of HPET tick that stands for * 1/(2^10) second, namely, 0.9765625 milliseconds */#define HPET_TINY_TIME_SPAN ((h->stime_freq >> 10) / STIME_PER_HPET_TICK)static void hpet_set_timer(HPETState *h, unsigned int tn){ uint64_t tn_cmp, cur_tick, diff; ASSERT(tn < HPET_TIMER_NUM); ASSERT(spin_is_locked(&h->lock)); 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_read_maincounter(h); if ( timer_is_32bit(h, tn) ) { tn_cmp = (uint32_t)tn_cmp; cur_tick = (uint32_t)cur_tick; } diff = tn_cmp - cur_tick; /* * Detect time values set in the past. This is hard to do for 32-bit * comparators as the timer does not have to be set that far in the future * for the counter difference to wrap a 32-bit signed integer. We fudge * by looking for a 'small' time value in the past. */ if ( (int64_t)diff < 0 ) diff = (timer_is_32bit(h, tn) && (-diff > HPET_TINY_TIME_SPAN)) ? (uint32_t)diff : 0; set_timer(&h->timers[tn], NOW() + hpet_tick_to_ns(h, diff));}static inline uint64_t hpet_fixup_reg( uint64_t new, uint64_t old, uint64_t mask){ new &= mask; new |= old & ~mask; return new;}static int hpet_write( struct vcpu *v, unsigned long addr, unsigned long length, unsigned long val){ HPETState *h = &v->domain->arch.hvm_domain.pl_time.vhpet; uint64_t old_val, new_val; int tn, i; addr &= HPET_MMAP_SIZE-1; if ( hpet_check_access_length(addr, length) != 0 ) goto out; spin_lock(&h->lock); old_val = hpet_read64(h, addr); if ( (addr & ~7) == HPET_COUNTER ) old_val = hpet_read_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 - guest_time_hpet(h->vcpu); for ( i = 0; i < HPET_TIMER_NUM; i++ ) hpet_set_timer(h, i); } 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 + guest_time_hpet(h->vcpu); for ( i = 0; i < HPET_TIMER_NUM; i++ ) hpet_stop_timer(h, i); } break; case HPET_COUNTER: if ( hpet_enabled(h) ) gdprintk(XENLOG_WARNING, "HPET: writing main counter but it's not halted!\n"); h->hpet.mc64 = new_val; break; case HPET_T0_CFG: case HPET_T1_CFG: case HPET_T2_CFG: tn = (addr - HPET_T0_CFG) >> 5;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?