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