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 + -
显示快捷键?