hpet.c

来自「xen虚拟机源代码安装包」· C语言 代码 · 共 599 行 · 第 1/2 页

C
599
字号
        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;            h->hpet.period[tn] = (uint32_t)h->hpet.period[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        {            /*             * Clamp period to reasonable min/max values:             *  - minimum is 900us, same as timers controlled by vpt.c             *  - maximum is to prevent overflow in time_after() calculations             */            if ( hpet_tick_to_ns(h, new_val) < MICROSECS(900) )                new_val = (MICROSECS(900) << 10) / h->hpet_to_ns_scale;            new_val &= (timer_is_32bit(h, tn) ? ~0u : ~0ull) >> 1;            h->hpet.period[tn] = new_val;        }        h->hpet.timers[tn].config &= ~HPET_TN_SETVAL;        if ( hpet_enabled(h) )            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].fsb = new_val;        break;    default:        /* Ignore writes to unsupported and reserved registers. */        break;    }    spin_unlock(&h->lock); out:    return X86EMUL_OKAY;}static int hpet_range(struct vcpu *v, unsigned long addr){    return (v->domain->arch.hvm_domain.params[HVM_PARAM_HPET_ENABLED] &&            (addr >= HPET_BASE_ADDRESS) &&            (addr < (HPET_BASE_ADDRESS + HPET_MMAP_SIZE)));}struct hvm_mmio_handler hpet_mmio_handler = {    .check_handler = hpet_range,    .read_handler  = hpet_read,    .write_handler = hpet_write};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;    ASSERT(spin_is_locked(&h->lock));    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)) )    {        gdprintk(XENLOG_ERR,                 "HPET: timer%u: invalid interrupt route config\n", tn);        domain_crash(d);        return;    }    /* We support only edge-triggered interrupt. */    spin_lock(&d->arch.hvm_domain.irq_lock);    vioapic_irq_positive_edge(d, tn_int_route);    spin_unlock(&d->arch.hvm_domain.irq_lock);}static void hpet_timer_fn(void *opaque){    struct HPET_timer_fn_info *htfi = opaque;    HPETState *h = htfi->hs;    unsigned int tn = htfi->tn;    spin_lock(&h->lock);    if ( !hpet_enabled(h) )    {        spin_unlock(&h->lock);        return;    }    if ( timer_config(h, tn) & HPET_TN_ENABLE )        hpet_route_interrupt(h, tn);    if ( timer_is_periodic(h, tn) && (h->hpet.period[tn] != 0) )    {        uint64_t mc = hpet_read_maincounter(h), period = h->hpet.period[tn];        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 + period);        }        else        {            while ( hpet_time_after64(mc, h->hpet.timers[tn].cmp) )                h->hpet.timers[tn].cmp += period;        }        set_timer(&h->timers[tn], NOW() + hpet_tick_to_ns(h, period));    }    spin_unlock(&h->lock);}void hpet_migrate_timers(struct vcpu *v){    struct HPETState *h = &v->domain->arch.hvm_domain.pl_time.vhpet;    int i;    if ( v != h->vcpu )        return;    for ( i = 0; i < HPET_TIMER_NUM; i++ )        migrate_timer(&h->timers[i], v->processor);}static int hpet_save(struct domain *d, hvm_domain_context_t *h){    HPETState *hp = &d->arch.hvm_domain.pl_time.vhpet;    int rc;    spin_lock(&hp->lock);    /* Write the proper value into the main counter */    hp->hpet.mc64 = hp->mc_offset + guest_time_hpet(hp->vcpu);    /* Save the HPET registers */    rc = _hvm_init_entry(h, HVM_SAVE_CODE(HPET), 0, HVM_SAVE_LENGTH(HPET));    if ( rc == 0 )    {        struct hvm_hw_hpet *rec = (struct hvm_hw_hpet *)&h->data[h->cur];        h->cur += HVM_SAVE_LENGTH(HPET);        memset(rec, 0, HVM_SAVE_LENGTH(HPET));#define C(x) rec->x = hp->hpet.x        C(capability);        C(config);        C(isr);        C(mc64);        C(timers[0].config);        C(timers[0].cmp);        C(timers[0].fsb);        C(timers[1].config);        C(timers[1].cmp);        C(timers[1].fsb);        C(timers[2].config);        C(timers[2].cmp);        C(timers[2].fsb);        C(period[0]);        C(period[1]);        C(period[2]);#undef C    }    spin_unlock(&hp->lock);    return rc;}static int hpet_load(struct domain *d, hvm_domain_context_t *h){    HPETState *hp = &d->arch.hvm_domain.pl_time.vhpet;    struct hvm_hw_hpet *rec;    int i;    spin_lock(&hp->lock);    /* Reload the HPET registers */    if ( _hvm_check_entry(h, HVM_SAVE_CODE(HPET), HVM_SAVE_LENGTH(HPET)) )    {        spin_unlock(&hp->lock);        return -EINVAL;    }    rec = (struct hvm_hw_hpet *)&h->data[h->cur];    h->cur += HVM_SAVE_LENGTH(HPET);#define C(x) hp->hpet.x = rec->x        C(capability);        C(config);        C(isr);        C(mc64);        C(timers[0].config);        C(timers[0].cmp);        C(timers[0].fsb);        C(timers[1].config);        C(timers[1].cmp);        C(timers[1].fsb);        C(timers[2].config);        C(timers[2].cmp);        C(timers[2].fsb);        C(period[0]);        C(period[1]);        C(period[2]);#undef C        /* Recalculate the offset between the main counter and guest time */    hp->mc_offset = hp->hpet.mc64 - guest_time_hpet(hp->vcpu);                    /* Restart the timers */    for ( i = 0; i < HPET_TIMER_NUM; i++ )        if ( hpet_enabled(hp) )            hpet_set_timer(hp, i);    spin_unlock(&hp->lock);    return 0;}HVM_REGISTER_SAVE_RESTORE(HPET, hpet_save, hpet_load, 1, HVMSR_PER_DOM);void hpet_init(struct vcpu *v){    HPETState *h = &v->domain->arch.hvm_domain.pl_time.vhpet;    int i;    memset(h, 0, sizeof(HPETState));    spin_lock_init(&h->lock);    h->vcpu = v;    h->stime_freq = S_TO_NS;    h->hpet_to_ns_scale = ((S_TO_NS * STIME_PER_HPET_TICK) << 10) / h->stime_freq;    h->hpet_to_ns_limit = ~0ULL / h->hpet_to_ns_scale;    /* 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 to be 1/16 of Xen system time */    h->hpet.capability |= ((S_TO_FS*STIME_PER_HPET_TICK/h->stime_freq) << 32);    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],                   v->processor);    }}void hpet_deinit(struct domain *d){    int i;    HPETState *h = &d->arch.hvm_domain.pl_time.vhpet;    for ( i = 0; i < HPET_TIMER_NUM; i++ )        kill_timer(&h->timers[i]);}void hpet_reset(struct domain *d){    hpet_deinit(d);    hpet_init(d->vcpu[0]);}

⌨️ 快捷键说明

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