⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 i8254.c

📁 xen 3.2.2 源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * QEMU 8253/8254 interval timer emulation *  * Copyright (c) 2003-2004 Fabrice Bellard * Copyright (c) 2006 Intel Corperation * Copyright (c) 2007 Keir Fraser, XenSource Inc. *  * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */#include <xen/config.h>#include <xen/types.h>#include <xen/mm.h>#include <xen/xmalloc.h>#include <xen/lib.h>#include <xen/errno.h>#include <xen/sched.h>#include <asm/hvm/hvm.h>#include <asm/hvm/io.h>#include <asm/hvm/support.h>#include <asm/hvm/vpt.h>#include <asm/current.h>#define domain_vpit(d)   (&(d)->arch.hvm_domain.pl_time.vpit)#define vcpu_vpit(vcpu)  (domain_vpit((vcpu)->domain))#define vpit_domain(pit) (container_of((pit), struct domain, \                                       arch.hvm_domain.pl_time.vpit))#define vpit_vcpu(pit)   (vpit_domain(pit)->vcpu[0])#define RW_STATE_LSB 1#define RW_STATE_MSB 2#define RW_STATE_WORD0 3#define RW_STATE_WORD1 4static int handle_pit_io(    int dir, uint32_t port, uint32_t bytes, uint32_t *val);static int handle_speaker_io(    int dir, uint32_t port, uint32_t bytes, uint32_t *val);/* Compute with 96 bit intermediate result: (a*b)/c */static uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c){    union {        uint64_t ll;        struct {#ifdef WORDS_BIGENDIAN            uint32_t high, low;#else            uint32_t low, high;#endif                    } l;    } u, res;    uint64_t rl, rh;    u.ll = a;    rl = (uint64_t)u.l.low * (uint64_t)b;    rh = (uint64_t)u.l.high * (uint64_t)b;    rh += (rl >> 32);    res.l.high = rh / c;    res.l.low = (((rh % c) << 32) + (rl & 0xffffffff)) / c;    return res.ll;}static int pit_get_count(PITState *pit, int channel){    uint64_t d;    int  counter;    struct hvm_hw_pit_channel *c = &pit->hw.channels[channel];    struct vcpu *v = vpit_vcpu(pit);    ASSERT(spin_is_locked(&pit->lock));    d = muldiv64(hvm_get_guest_time(v) - pit->count_load_time[channel],                 PIT_FREQ, ticks_per_sec(v));    switch ( c->mode )    {    case 0:    case 1:    case 4:    case 5:        counter = (c->count - d) & 0xffff;        break;    case 3:        /* XXX: may be incorrect for odd counts */        counter = c->count - ((2 * d) % c->count);        break;    default:        counter = c->count - (d % c->count);        break;    }    return counter;}static int pit_get_out(PITState *pit, int channel){    struct hvm_hw_pit_channel *s = &pit->hw.channels[channel];    uint64_t d;    int out;    struct vcpu *v = vpit_vcpu(pit);    ASSERT(spin_is_locked(&pit->lock));    d = muldiv64(hvm_get_guest_time(v) - pit->count_load_time[channel],                  PIT_FREQ, ticks_per_sec(v));    switch ( s->mode )    {    default:    case 0:        out = (d >= s->count);        break;    case 1:        out = (d < s->count);        break;    case 2:        out = (((d % s->count) == 0) && (d != 0));        break;    case 3:        out = ((d % s->count) < ((s->count + 1) >> 1));        break;    case 4:    case 5:        out = (d == s->count);        break;    }    return out;}static void pit_set_gate(PITState *pit, int channel, int val){    struct hvm_hw_pit_channel *s = &pit->hw.channels[channel];    struct vcpu *v = vpit_vcpu(pit);    ASSERT(spin_is_locked(&pit->lock));    switch ( s->mode )    {    default:    case 0:    case 4:        /* XXX: just disable/enable counting */        break;    case 1:    case 5:    case 2:    case 3:        /* Restart counting on rising edge. */        if ( s->gate < val )            pit->count_load_time[channel] = hvm_get_guest_time(v);        break;    }    s->gate = val;}int pit_get_gate(PITState *pit, int channel){    ASSERT(spin_is_locked(&pit->lock));    return pit->hw.channels[channel].gate;}static void pit_time_fired(struct vcpu *v, void *priv){    uint64_t *count_load_time = priv;    *count_load_time = hvm_get_guest_time(v);}static void pit_load_count(PITState *pit, int channel, int val){    u32 period;    struct hvm_hw_pit_channel *s = &pit->hw.channels[channel];    struct vcpu *v = vpit_vcpu(pit);    ASSERT(spin_is_locked(&pit->lock));    if ( val == 0 )        val = 0x10000;    if ( v == NULL )        rdtscll(pit->count_load_time[channel]);    else        pit->count_load_time[channel] = hvm_get_guest_time(v);    s->count = val;    period = DIV_ROUND((val * 1000000000ULL), PIT_FREQ);    if ( (v == NULL) || !is_hvm_vcpu(v) || (channel != 0) )        return;    switch ( s->mode )    {    case 2:    case 3:        /* Periodic timer. */        create_periodic_time(v, &pit->pt0, period, 0, 0, pit_time_fired,                              &pit->count_load_time[channel]);        break;    case 1:    case 4:        /* One-shot timer. */        create_periodic_time(v, &pit->pt0, period, 0, 1, pit_time_fired,                             &pit->count_load_time[channel]);        break;    default:        destroy_periodic_time(&pit->pt0);        break;    }}static void pit_latch_count(PITState *pit, int channel){    struct hvm_hw_pit_channel *c = &pit->hw.channels[channel];    ASSERT(spin_is_locked(&pit->lock));    if ( !c->count_latched )    {        c->latched_count = pit_get_count(pit, channel);        c->count_latched = c->rw_mode;    }}static void pit_latch_status(PITState *pit, int channel){    struct hvm_hw_pit_channel *c = &pit->hw.channels[channel];    ASSERT(spin_is_locked(&pit->lock));    if ( !c->status_latched )    {        /* TODO: Return NULL COUNT (bit 6). */        c->status = ((pit_get_out(pit, channel) << 7) |                     (c->rw_mode << 4) |                     (c->mode << 1) |                     c->bcd);        c->status_latched = 1;    }}static void pit_ioport_write(struct PITState *pit, uint32_t addr, uint32_t val){    int channel, access;    struct hvm_hw_pit_channel *s;    val  &= 0xff;    addr &= 3;    spin_lock(&pit->lock);    if ( addr == 3 )    {        channel = val >> 6;        if ( channel == 3 )        {            /* Read-Back Command. */            for ( channel = 0; channel < 3; channel++ )            {                s = &pit->hw.channels[channel];                if ( val & (2 << channel) )                {                    if ( !(val & 0x20) )                        pit_latch_count(pit, channel);                    if ( !(val & 0x10) )                        pit_latch_status(pit, channel);                }            }        }        else        {            /* Select Counter <channel>. */            s = &pit->hw.channels[channel];            access = (val >> 4) & 3;            if ( access == 0 )            {                pit_latch_count(pit, channel);            }            else            {                s->rw_mode = access;                s->read_state = access;                s->write_state = access;                s->mode = (val >> 1) & 7;                if ( s->mode > 5 )                    s->mode -= 4;                s->bcd = val & 1;                /* XXX: update irq timer ? */            }        }    }    else    {        /* Write Count. */        s = &pit->hw.channels[addr];        switch ( s->write_state )        {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -