diff -r c4eead8a925b tools/ioemu/hw/pc.c --- a/tools/ioemu/hw/pc.c Sun Apr 16 15:41:31 2006 +0100 +++ b/tools/ioemu/hw/pc.c Tue Apr 18 19:30:06 2006 +0800 @@ -40,7 +40,6 @@ int dummy_refresh_clock; int dummy_refresh_clock; static fdctrl_t *floppy_controller; static RTCState *rtc_state; -static PITState *pit; static void ioport80_write(void *opaque, uint32_t addr, uint32_t data) { @@ -243,17 +242,13 @@ static void cmos_init(uint64_t ram_size, static void speaker_ioport_write(void *opaque, uint32_t addr, uint32_t val) { - speaker_data_on = (val >> 1) & 1; - pit_set_gate(pit, 2, val & 1); + fprintf(stderr, "speaker port should not be handled in DM!\n"); } static uint32_t speaker_ioport_read(void *opaque, uint32_t addr) { - int out; - out = pit_get_out(pit, 2, qemu_get_clock(vm_clock)); - dummy_refresh_clock ^= 1; - return (speaker_data_on << 1) | pit_get_gate(pit, 2) | (out << 5) | - (dummy_refresh_clock << 4); + fprintf(stderr, "speaker port should not be handled in DM!\n"); + return 0; } static void ioport92_write(void *opaque, uint32_t addr, uint32_t val) @@ -529,7 +524,6 @@ void pc_init(uint64_t ram_size, int vga_ register_ioport_write(0x92, 1, 1, ioport92_write, NULL); pic_init(); - pit = pit_init(0x40, 0); for(i = 0; i < MAX_SERIAL_PORTS; i++) { if (serial_hds[i]) { diff -r c4eead8a925b tools/ioemu/target-i386-dm/Makefile --- a/tools/ioemu/target-i386-dm/Makefile Sun Apr 16 15:41:31 2006 +0100 +++ b/tools/ioemu/target-i386-dm/Makefile Tue Apr 18 19:30:06 2006 +0800 @@ -277,7 +277,7 @@ endif # Hardware support VL_OBJS+= ide.o ne2000.o pckbd.o vga.o dma.o -VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259_stub.o i8254.o pc.o port-e9.o +VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259_stub.o pc.o port-e9.o VL_OBJS+= cirrus_vga.o pcnet.o VL_OBJS+= $(SOUND_HW) $(AUDIODRV) mixeng.o diff -r c4eead8a925b xen/arch/x86/hvm/Makefile --- a/xen/arch/x86/hvm/Makefile Sun Apr 16 15:41:31 2006 +0100 +++ b/xen/arch/x86/hvm/Makefile Tue Apr 18 19:30:06 2006 +0800 @@ -2,6 +2,7 @@ subdir-y += vmx subdir-y += vmx obj-y += hvm.o +obj-y += i8254.o obj-y += i8259.o obj-y += intercept.o obj-y += io.o diff -r c4eead8a925b xen/arch/x86/hvm/hvm.c --- a/xen/arch/x86/hvm/hvm.c Sun Apr 16 15:41:31 2006 +0100 +++ b/xen/arch/x86/hvm/hvm.c Tue Apr 18 19:30:06 2006 +0800 @@ -203,6 +203,8 @@ void hvm_setup_platform(struct domain* d spin_lock_init(&d->arch.hvm_domain.round_robin_lock); hvm_vioapic_init(d); } + + pit_init(&platform->vpit, current); } void pic_irq_request(void *data, int level) diff -r c4eead8a925b xen/arch/x86/hvm/intercept.c --- a/xen/arch/x86/hvm/intercept.c Sun Apr 16 15:41:31 2006 +0100 +++ b/xen/arch/x86/hvm/intercept.c Tue Apr 18 19:30:06 2006 +0800 @@ -206,139 +206,6 @@ int register_io_handler(unsigned long ad return 1; } -static void pit_cal_count(struct hvm_virpit *vpit) -{ - u64 nsec_delta = (unsigned int)((NOW() - vpit->count_point)); - - nsec_delta += vpit->count_advance; - if (nsec_delta > vpit->period) - HVM_DBG_LOG(DBG_LEVEL_1, - "HVM_PIT: long time has passed from last injection!"); - - if(vpit->init_val == 0) - { - printk("PIT init value == 0!\n"); - domain_crash_synchronous(); - } - - vpit->count = vpit->init_val - - ((nsec_delta * PIT_FREQ / 1000000000ULL) % vpit->init_val); -} - -static void pit_latch_io(struct hvm_virpit *vpit) -{ - pit_cal_count(vpit); - - switch(vpit->read_state) { - case MSByte: - vpit->count_MSB_latched=1; - break; - case LSByte: - vpit->count_LSB_latched=1; - break; - case LSByte_multiple: - vpit->count_LSB_latched=1; - vpit->count_MSB_latched=1; - break; - case MSByte_multiple: - HVM_DBG_LOG(DBG_LEVEL_1, - "HVM_PIT: latch PIT counter before MSB_multiple!"); - vpit->read_state=LSByte_multiple; - vpit->count_LSB_latched=1; - vpit->count_MSB_latched=1; - break; - default: - domain_crash_synchronous(); - } -} - -static int pit_read_io(struct hvm_virpit *vpit) -{ - if(vpit->count_LSB_latched) { - /* Read Least Significant Byte */ - if(vpit->read_state==LSByte_multiple) { - vpit->read_state=MSByte_multiple; - } - vpit->count_LSB_latched=0; - return (vpit->count & 0xFF); - } else if(vpit->count_MSB_latched) { - /* Read Most Significant Byte */ - if(vpit->read_state==MSByte_multiple) { - vpit->read_state=LSByte_multiple; - } - vpit->count_MSB_latched=0; - return ((vpit->count>>8) & 0xFF); - } else { - /* Unlatched Count Read */ - HVM_DBG_LOG(DBG_LEVEL_1, "HVM_PIT: unlatched read"); - pit_cal_count(vpit); - if(!(vpit->read_state & 0x1)) { - /* Read Least Significant Byte */ - if(vpit->read_state==LSByte_multiple) { - vpit->read_state=MSByte_multiple; - } - return (vpit->count & 0xFF); - } else { - /* Read Most Significant Byte */ - if(vpit->read_state==MSByte_multiple) { - vpit->read_state=LSByte_multiple; - } - return ((vpit->count>>8) & 0xFF); - } - } -} - -/* hvm_io_assist light-weight version, specific to PIT DM */ -static void resume_pit_io(ioreq_t *p) -{ - struct cpu_user_regs *regs = guest_cpu_user_regs(); - unsigned long old_eax = regs->eax; - p->state = STATE_INVALID; - - switch(p->size) { - case 1: - regs->eax = (old_eax & 0xffffff00) | (p->u.data & 0xff); - break; - case 2: - regs->eax = (old_eax & 0xffff0000) | (p->u.data & 0xffff); - break; - case 4: - regs->eax = (p->u.data & 0xffffffff); - break; - default: - BUG(); - } -} - -/* the intercept action for PIT DM retval:0--not handled; 1--handled */ -int intercept_pit_io(ioreq_t *p) -{ - struct vcpu *v = current; - struct hvm_virpit *vpit = &(v->domain->arch.hvm_domain.vpit); - - if (p->size != 1 || - p->pdata_valid || - p->type != IOREQ_TYPE_PIO) - return 0; - - if (p->addr == PIT_MODE && - p->dir == 0 && /* write */ - ((p->u.data >> 4) & 0x3) == 0 && /* latch command */ - ((p->u.data >> 6) & 0x3) == (vpit->channel)) {/* right channel */ - pit_latch_io(vpit); - return 1; - } - - if (p->addr == (PIT_CH0 + vpit->channel) && - p->dir == 1) { /* read */ - p->u.data = pit_read_io(vpit); - resume_pit_io(p); - return 1; - } - - return 0; -} - /* hooks function for the HLT instruction emulation wakeup */ void hlt_timer_fn(void *data) { @@ -347,109 +214,6 @@ void hlt_timer_fn(void *data) evtchn_set_pending(v, iopacket_port(v)); } -static __inline__ void missed_ticks(struct hvm_virpit*vpit) -{ - int missed_ticks; - - missed_ticks = (NOW() - vpit->scheduled)/(s_time_t) vpit->period; - if ( missed_ticks++ >= 0 ) { - vpit->pending_intr_nr += missed_ticks; - vpit->scheduled += missed_ticks * vpit->period; - } -} - -/* hooks function for the PIT when the guest is active */ -static void pit_timer_fn(void *data) -{ - struct vcpu *v = data; - struct hvm_virpit *vpit = &(v->domain->arch.hvm_domain.vpit); - - /* pick up missed timer tick */ - missed_ticks(vpit); - if ( test_bit(_VCPUF_running, &v->vcpu_flags) ) { - set_timer(&vpit->pit_timer, vpit->scheduled); - } -} - -/* pick up missed timer ticks at deactive time */ -void pickup_deactive_ticks(struct hvm_virpit *vpit) -{ - if ( !active_timer(&(vpit->pit_timer)) ) { - missed_ticks(vpit); - set_timer(&vpit->pit_timer, vpit->scheduled); - } -} - -/* Only some PIT operations such as load init counter need a hypervisor hook. - * leave all other operations in user space DM - */ -void hvm_hooks_assist(struct vcpu *v) -{ - vcpu_iodata_t *vio = get_vio(v->domain, v->vcpu_id); - ioreq_t *p = &vio->vp_ioreq; - struct hvm_virpit *vpit = &(v->domain->arch.hvm_domain.vpit); - int rw_mode, reinit = 0; - - /* load init count*/ - if (p->state == STATE_IORESP_HOOK) { - /* set up actimer, handle re-init */ - if ( active_timer(&(vpit->pit_timer)) ) { - HVM_DBG_LOG(DBG_LEVEL_1, "HVM_PIT: guest reset PIT with channel %lx!\n", (unsigned long) ((p->u.data >> 24) & 0x3) ); - stop_timer(&(vpit->pit_timer)); - reinit = 1; - - } - else { - init_timer(&vpit->pit_timer, pit_timer_fn, v, v->processor); - } - - /* init count for this channel */ - vpit->init_val = (p->u.data & 0xFFFF) ; - /* frequency(ns) of pit */ - vpit->period = DIV_ROUND(((vpit->init_val) * 1000000000ULL), PIT_FREQ); - HVM_DBG_LOG(DBG_LEVEL_1,"HVM_PIT: guest set init pit freq:%u ns, initval:0x%x\n", vpit->period, vpit->init_val); - if (vpit->period < 900000) { /* < 0.9 ms */ - printk("HVM_PIT: guest programmed too small an init_val: %x\n", - vpit->init_val); - vpit->period = 1000000; - } - vpit->period_cycles = (u64)vpit->period * cpu_khz / 1000000L; - printk("HVM_PIT: guest freq in cycles=%lld\n",(long long)vpit->period_cycles); - - vpit->channel = ((p->u.data >> 24) & 0x3); - vpit->first_injected = 0; - - vpit->count_LSB_latched = 0; - vpit->count_MSB_latched = 0; - - rw_mode = ((p->u.data >> 26) & 0x3); - switch(rw_mode) { - case 0x1: - vpit->read_state=LSByte; - break; - case 0x2: - vpit->read_state=MSByte; - break; - case 0x3: - vpit->read_state=LSByte_multiple; - break; - default: - printk("HVM_PIT:wrong PIT rw_mode!\n"); - break; - } - - vpit->scheduled = NOW() + vpit->period; - set_timer(&vpit->pit_timer, vpit->scheduled); - - /*restore the state*/ - p->state = STATE_IORESP_READY; - - /* register handler to intercept the PIT io when vm_exit */ - if (!reinit) { - register_portio_handler(0x40, 4, intercept_pit_io); - } - } -} /* * Local variables: diff -r c4eead8a925b xen/arch/x86/hvm/io.c --- a/xen/arch/x86/hvm/io.c Sun Apr 16 15:41:31 2006 +0100 +++ b/xen/arch/x86/hvm/io.c Tue Apr 18 19:30:06 2006 +0800 @@ -674,8 +674,6 @@ void hvm_io_assist(struct vcpu *v) } p = &vio->vp_ioreq; - if (p->state == STATE_IORESP_HOOK) - hvm_hooks_assist(v); /* clear IO wait HVM flag */ if (test_bit(ARCH_HVM_IO_WAIT, &v->arch.hvm_vcpu.ioflags)) { diff -r c4eead8a925b xen/arch/x86/hvm/svm/intr.c --- a/xen/arch/x86/hvm/svm/intr.c Sun Apr 16 15:41:31 2006 +0100 +++ b/xen/arch/x86/hvm/svm/intr.c Tue Apr 18 19:30:06 2006 +0800 @@ -46,44 +46,43 @@ u64 svm_get_guest_time(struct vcpu *v) { - struct hvm_virpit *vpit = &(v->domain->arch.hvm_domain.vpit); + struct hvm_time_info *time_info = &(v->domain->arch.hvm_domain.vpit.time_info); u64 host_tsc; rdtscll(host_tsc); - return host_tsc + vpit->cache_tsc_offset; + return host_tsc + time_info->cache_tsc_offset; } void svm_set_guest_time(struct vcpu *v, u64 gtime) { - struct hvm_virpit *vpit = &(v->domain->arch.hvm_domain.vpit); + struct hvm_time_info *time_info = &(v->domain->arch.hvm_domain.vpit.time_info); u64 host_tsc; rdtscll(host_tsc); - vpit->cache_tsc_offset = gtime - host_tsc; - v->arch.hvm_svm.vmcb->tsc_offset = vpit->cache_tsc_offset; + time_info->cache_tsc_offset = gtime - host_tsc; + v->arch.hvm_svm.vmcb->tsc_offset = time_info->cache_tsc_offset; } static inline void interrupt_post_injection(struct vcpu * v, int vector, int type) { struct hvm_virpit *vpit = &(v->domain->arch.hvm_domain.vpit); + struct hvm_time_info *time_info = &vpit->time_info; if ( is_pit_irq(v, vector, type) ) { - if ( !vpit->first_injected ) { - vpit->pending_intr_nr = 0; - vpit->last_pit_gtime = svm_get_guest_time(v); - vpit->scheduled = NOW() + vpit->period; - set_timer(&vpit->pit_timer, vpit->scheduled); - vpit->first_injected = 1; + if ( !time_info->first_injected ) { + time_info->pending_intr_nr = 0; + time_info->last_pit_gtime = svm_get_guest_time(v); + time_info->first_injected = 1; } else { - vpit->pending_intr_nr--; + time_info->pending_intr_nr--; } - vpit->count_advance = 0; - vpit->count_point = NOW(); - - vpit->last_pit_gtime += vpit->period_cycles; - svm_set_guest_time(v, vpit->last_pit_gtime); + time_info->count_advance = 0; + time_info->count_point = NOW(); + + time_info->last_pit_gtime += time_info->period_cycles; + svm_set_guest_time(v, time_info->last_pit_gtime); } switch(type) @@ -123,6 +122,7 @@ asmlinkage void svm_intr_assist(void) struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb; struct hvm_domain *plat=&v->domain->arch.hvm_domain; struct hvm_virpit *vpit = &plat->vpit; + struct hvm_time_info *time_info = &vpit->time_info; struct hvm_virpic *pic= &plat->vpic; int intr_type = VLAPIC_DELIV_MODE_EXT; int intr_vector = -1; @@ -185,7 +185,7 @@ asmlinkage void svm_intr_assist(void) if ( cpu_has_pending_irq(v) ) { intr_vector = cpu_get_interrupt(v, &intr_type); } - else if ( (v->vcpu_id == 0) && vpit->pending_intr_nr ) { + else if ( (v->vcpu_id == 0) && time_info->pending_intr_nr ) { pic_set_irq(pic, 0, 0); pic_set_irq(pic, 0, 1); intr_vector = cpu_get_interrupt(v, &intr_type); @@ -201,7 +201,7 @@ asmlinkage void svm_intr_assist(void) /* Re-injecting a PIT interruptt? */ if (re_injecting && is_pit_irq(v, intr_vector, intr_type)) { - ++vpit->pending_intr_nr; + ++time_info->pending_intr_nr; } /* let's inject this interrupt */ TRACE_3D(TRC_VMX_INT, v->domain->domain_id, intr_vector, 0); diff -r c4eead8a925b xen/arch/x86/hvm/svm/svm.c --- a/xen/arch/x86/hvm/svm/svm.c Sun Apr 16 15:41:31 2006 +0100 +++ b/xen/arch/x86/hvm/svm/svm.c Tue Apr 18 19:30:06 2006 +0800 @@ -675,12 +675,12 @@ static void arch_svm_do_launch(struct vc static void svm_freeze_time(struct vcpu *v) { - struct hvm_virpit *vpit = &v->domain->arch.hvm_domain.vpit; + struct hvm_time_info *time_info = &v->domain->arch.hvm_domain.vpit.time_info; - if ( vpit->first_injected && !v->domain->arch.hvm_domain.guest_time ) { + if ( time_info->first_injected && !v->domain->arch.hvm_domain.guest_time ) { v->domain->arch.hvm_domain.guest_time = svm_get_guest_time(v); - vpit->count_advance += (NOW() - vpit->count_point); - stop_timer(&(vpit->pit_timer)); + time_info->count_advance += (NOW() - time_info->count_point); + stop_timer(&(time_info->pit_timer)); } } @@ -750,7 +750,7 @@ static void svm_relinquish_guest_resourc } } - kill_timer(&d->arch.hvm_domain.vpit.pit_timer); + kill_timer(&d->arch.hvm_domain.vpit.time_info.pit_timer); if ( d->arch.hvm_domain.shared_page_va ) unmap_domain_page_global( @@ -780,10 +780,10 @@ void arch_svm_do_resume(struct vcpu *v) void svm_migrate_timers(struct vcpu *v) { - struct hvm_virpit *vpit = &(v->domain->arch.hvm_domain.vpit); - - migrate_timer( &vpit->pit_timer, v->processor ); - migrate_timer( &v->arch.hvm_svm.hlt_timer, v->processor ); + struct hvm_time_info *time_info = &v->domain->arch.hvm_domain.vpit.time_info; + + migrate_timer(&time_info->pit_timer, v->processor); + migrate_timer(&v->arch.hvm_svm.hlt_timer, v->processor); if ( hvm_apic_support(v->domain) && VLAPIC( v )) migrate_timer( &(VLAPIC(v)->vlapic_timer ), v->processor ); } @@ -1843,11 +1843,11 @@ static inline void svm_do_msr_access(str switch (regs->ecx) { case MSR_IA32_TIME_STAMP_COUNTER: { - struct hvm_virpit *vpit; + struct hvm_time_info *time_info; rdtscll(msr_content); - vpit = &(v->domain->arch.hvm_domain.vpit); - msr_content += vpit->cache_tsc_offset; + time_info = &v->domain->arch.hvm_domain.vpit.time_info; + msr_content += time_info->cache_tsc_offset; break; } case MSR_IA32_SYSENTER_CS: diff -r c4eead8a925b xen/arch/x86/hvm/svm/vmcb.c --- a/xen/arch/x86/hvm/svm/vmcb.c Sun Apr 16 15:41:31 2006 +0100 +++ b/xen/arch/x86/hvm/svm/vmcb.c Tue Apr 18 19:30:06 2006 +0800 @@ -478,14 +478,15 @@ void svm_do_resume(struct vcpu *v) { struct domain *d = v->domain; struct hvm_virpit *vpit = &d->arch.hvm_domain.vpit; + struct hvm_time_info *time_info = &vpit->time_info; svm_stts(v); /* pick up the elapsed PIT ticks and re-enable pit_timer */ - if ( vpit->first_injected ) { + if ( time_info->first_injected ) { if ( v->domain->arch.hvm_domain.guest_time ) { svm_set_guest_time(v, v->domain->arch.hvm_domain.guest_time); - vpit->count_point = NOW(); + time_info->count_point = NOW(); v->domain->arch.hvm_domain.guest_time = 0; } pickup_deactive_ticks(vpit); diff -r c4eead8a925b xen/arch/x86/hvm/vmx/io.c --- a/xen/arch/x86/hvm/vmx/io.c Sun Apr 16 15:41:31 2006 +0100 +++ b/xen/arch/x86/hvm/vmx/io.c Tue Apr 18 19:30:06 2006 +0800 @@ -51,44 +51,43 @@ void __set_tsc_offset(u64 offset) u64 get_guest_time(struct vcpu *v) { - struct hvm_virpit *vpit = &(v->domain->arch.hvm_domain.vpit); + struct hvm_time_info *time_info = &(v->domain->arch.hvm_domain.vpit.time_info); u64 host_tsc; rdtscll(host_tsc); - return host_tsc + vpit->cache_tsc_offset; + return host_tsc + time_info->cache_tsc_offset; } void set_guest_time(struct vcpu *v, u64 gtime) { - struct hvm_virpit *vpit = &(v->domain->arch.hvm_domain.vpit); + struct hvm_time_info *time_info = &(v->domain->arch.hvm_domain.vpit.time_info); u64 host_tsc; rdtscll(host_tsc); - vpit->cache_tsc_offset = gtime - host_tsc; - __set_tsc_offset(vpit->cache_tsc_offset); + time_info->cache_tsc_offset = gtime - host_tsc; + __set_tsc_offset(time_info->cache_tsc_offset); } static inline void interrupt_post_injection(struct vcpu * v, int vector, int type) { struct hvm_virpit *vpit = &(v->domain->arch.hvm_domain.vpit); + struct hvm_time_info *time_info = &vpit->time_info; if ( is_pit_irq(v, vector, type) ) { - if ( !vpit->first_injected ) { - vpit->pending_intr_nr = 0; - vpit->last_pit_gtime = get_guest_time(v); - vpit->scheduled = NOW() + vpit->period; - set_timer(&vpit->pit_timer, vpit->scheduled); - vpit->first_injected = 1; + if ( !time_info->first_injected ) { + time_info->pending_intr_nr = 0; + time_info->last_pit_gtime = get_guest_time(v); + time_info->first_injected = 1; } else { - vpit->pending_intr_nr--; + time_info->pending_intr_nr--; } - vpit->count_advance = 0; - vpit->count_point = NOW(); - - vpit->last_pit_gtime += vpit->period_cycles; - set_guest_time(v, vpit->last_pit_gtime); + time_info->count_advance = 0; + time_info->count_point = NOW(); + + time_info->last_pit_gtime += time_info->period_cycles; + set_guest_time(v, time_info->last_pit_gtime); } switch(type) @@ -152,13 +151,13 @@ asmlinkage void vmx_intr_assist(void) unsigned long eflags; struct vcpu *v = current; struct hvm_domain *plat=&v->domain->arch.hvm_domain; - struct hvm_virpit *vpit = &plat->vpit; + struct hvm_time_info *time_info = &plat->vpit.time_info; struct hvm_virpic *pic= &plat->vpic; if ( v->vcpu_id == 0 ) hvm_pic_assist(v); - if ( (v->vcpu_id == 0) && vpit->pending_intr_nr ) { + if ( (v->vcpu_id == 0) && time_info->pending_intr_nr ) { pic_set_irq(pic, 0, 0); pic_set_irq(pic, 0, 1); } @@ -203,13 +202,14 @@ void vmx_do_resume(struct vcpu *v) { struct domain *d = v->domain; struct hvm_virpit *vpit = &v->domain->arch.hvm_domain.vpit; + struct hvm_time_info *time_info = &vpit->time_info; vmx_stts(); /* pick up the elapsed PIT ticks and re-enable pit_timer */ - if ( vpit->first_injected ) { + if ( time_info->first_injected ) { if ( v->domain->arch.hvm_domain.guest_time ) { - vpit->count_point = NOW(); + time_info->count_point = NOW(); set_guest_time(v, v->domain->arch.hvm_domain.guest_time); v->domain->arch.hvm_domain.guest_time = 0; } diff -r c4eead8a925b xen/arch/x86/hvm/vmx/vmx.c --- a/xen/arch/x86/hvm/vmx/vmx.c Sun Apr 16 15:41:31 2006 +0100 +++ b/xen/arch/x86/hvm/vmx/vmx.c Tue Apr 18 19:30:06 2006 +0800 @@ -102,7 +102,7 @@ static void vmx_relinquish_guest_resourc } } - kill_timer(&d->arch.hvm_domain.vpit.pit_timer); + kill_timer(&d->arch.hvm_domain.vpit.time_info.pit_timer); if ( d->arch.hvm_domain.shared_page_va ) unmap_domain_page_global( @@ -358,12 +358,12 @@ static inline int long_mode_do_msr_write static void vmx_freeze_time(struct vcpu *v) { - struct hvm_virpit *vpit = &v->domain->arch.hvm_domain.vpit; + struct hvm_time_info *time_info = &(v->domain->arch.hvm_domain.vpit.time_info); - if ( vpit->first_injected && !v->domain->arch.hvm_domain.guest_time ) { + if ( time_info->first_injected && !v->domain->arch.hvm_domain.guest_time ) { v->domain->arch.hvm_domain.guest_time = get_guest_time(v); - vpit->count_advance += (NOW() - vpit->count_point); - stop_timer(&(vpit->pit_timer)); + time_info->count_advance += (NOW() - time_info->count_point); + stop_timer(&(time_info->pit_timer)); } } @@ -393,9 +393,9 @@ int vmx_initialize_guest_resources(struc void vmx_migrate_timers(struct vcpu *v) { - struct hvm_virpit *vpit = &(v->domain->arch.hvm_domain.vpit); - - migrate_timer(&vpit->pit_timer, v->processor); + struct hvm_time_info *time_info = &v->domain->arch.hvm_domain.vpit.time_info; + + migrate_timer(&time_info->pit_timer, v->processor); migrate_timer(&v->arch.hvm_vmx.hlt_timer, v->processor); if ( hvm_apic_support(v->domain) && VLAPIC(v)) migrate_timer(&(VLAPIC(v)->vlapic_timer), v->processor); @@ -1836,11 +1836,11 @@ static inline void vmx_do_msr_read(struc switch (regs->ecx) { case MSR_IA32_TIME_STAMP_COUNTER: { - struct hvm_virpit *vpit; + struct hvm_time_info *time_info; rdtscll(msr_content); - vpit = &(v->domain->arch.hvm_domain.vpit); - msr_content += vpit->cache_tsc_offset; + time_info = &(v->domain->arch.hvm_domain.vpit.time_info); + msr_content += time_info->cache_tsc_offset; break; } case MSR_IA32_SYSENTER_CS: diff -r c4eead8a925b xen/include/asm-x86/hvm/vpit.h --- a/xen/include/asm-x86/hvm/vpit.h Sun Apr 16 15:41:31 2006 +0100 +++ b/xen/include/asm-x86/hvm/vpit.h Tue Apr 18 19:30:06 2006 +0800 @@ -30,47 +30,65 @@ #define PIT_FREQ 1193181 -#define LSByte 0 -#define MSByte 1 -#define LSByte_multiple 2 -#define MSByte_multiple 3 +#define PIT_BASE 0x40 +#define HVM_PIT_ACCEL_MODE 2 -struct hvm_virpit { - /* for simulation of counter 0 in mode 2 */ +typedef struct PITChannelState { + int count; /* can be 65536 */ + u16 latched_count; + u8 count_latched; + u8 status_latched; + u8 status; + u8 read_state; + u8 write_state; + u8 write_latch; + u8 rw_mode; + u8 mode; + u8 bcd; /* not supported */ + u8 gate; /* timer start */ + s64 count_load_time; + /* irq handling */ + s64 next_transition_time; + int irq; + struct hvm_time_info *hvm_time; + u32 period; /* period(ns) based on count */ +} PITChannelState; + +struct hvm_time_info { + /* extra info for the mode 2 channel */ + struct timer pit_timer; + struct vcpu *vcpu; /* which vcpu the ac_timer bound to */ u64 period_cycles; /* pit frequency in cpu cycles */ s_time_t count_advance; /* accumulated count advance since last fire */ s_time_t count_point; /* last point accumulating count advance */ - s_time_t scheduled; /* scheduled timer interrupt */ - struct timer pit_timer; /* periodic timer for mode 2*/ - unsigned int channel; /* the pit channel, counter 0~2 */ unsigned int pending_intr_nr; /* the couner for pending timer interrupts */ - u32 period; /* pit frequency in ns */ int first_injected; /* flag to prevent shadow window */ s64 cache_tsc_offset; /* cache of VMCS TSC_OFFSET offset */ u64 last_pit_gtime; /* guest time when last pit is injected */ +}; - /* virtual PIT state for handle related I/O */ - int read_state; - int count_LSB_latched; - int count_MSB_latched; +typedef struct hvm_virpit { + PITChannelState channels[3]; + struct hvm_time_info time_info; + int speaker_data_on; + int dummy_refresh_clock; +}hvm_virpit; - unsigned int count; /* the 16 bit channel count */ - unsigned int init_val; /* the init value for the counter */ -}; static __inline__ s_time_t get_pit_scheduled( struct vcpu *v, struct hvm_virpit *vpit) { + struct PITChannelState *s = &(vpit->channels[0]); if ( is_irq_enabled(v, 0) ) { - return vpit->scheduled; + return s->next_transition_time; } else return -1; } /* to hook the ioreq packet to get the PIT initialization info */ -extern void hvm_hooks_assist(struct vcpu *v); -void pickup_deactive_ticks(struct hvm_virpit *vpit); +extern void pit_init(struct hvm_virpit *pit, struct vcpu *v); +extern void pickup_deactive_ticks(struct hvm_virpit *vpit); #endif /* __ASM_X86_HVM_VPIT_H__ */ diff -r c4eead8a925b xen/arch/x86/hvm/i8254.c --- /dev/null Thu Jan 1 00:00:00 1970 +0000 +++ b/xen/arch/x86/hvm/i8254.c Tue Apr 18 19:30:06 2006 +0800 @@ -0,0 +1,594 @@ +/* + * QEMU 8253/8254 interval timer emulation + * + * Copyright (c) 2003-2004 Fabrice Bellard + * Copyright (c) 2006 Intel Corperation + * + * 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. + */ +/* Edwin Zhai + * Ported to xen: + * use actimer for intr generation; + * move speaker io access to hypervisor; + * use new method for counter/intrs calculation + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/*#define DEBUG_PIT*/ + +#define RW_STATE_LSB 1 +#define RW_STATE_MSB 2 +#define RW_STATE_WORD0 3 +#define RW_STATE_WORD1 4 + +#ifndef NSEC_PER_SEC +#define NSEC_PER_SEC (1000000000ULL) +#endif + +#ifndef TIMER_SLOP +#define TIMER_SLOP (50*1000) /* ns */ +#endif + +static void pit_irq_timer_update(PITChannelState *s, s64 current_time); + +s_time_t hvm_get_clock(void) +{ + /* TODO: add pause/unpause support */ + return NOW(); +} + +static int pit_get_count(PITChannelState *s) +{ + u64 d; + u64 counter; + + d = hvm_get_clock() - s->count_load_time; + switch(s->mode) { + case 0: + case 1: + case 4: + case 5: + counter = (s->period - d) & 0xffff; + break; + case 3: + /* XXX: may be incorrect for odd counts */ + counter = s->period - ((2 * d) % s->period); + break; + default: + /* mod 2 counter handle */ + d = hvm_get_clock() - s->hvm_time->count_point; + d += s->hvm_time->count_advance; + counter = s->period - (d % s->period); + break; + } + /* change from ns to pit counter */ + counter = DIV_ROUND( (counter * PIT_FREQ), NSEC_PER_SEC); + return counter; +} + +/* get pit output bit */ +static int pit_get_out1(PITChannelState *s, s64 current_time) +{ + u64 d; + int out; + + d = current_time - s->count_load_time; + switch(s->mode) { + default: + case 0: + out = (d >= s->period); + break; + case 1: + out = (d < s->period); + break; + case 2: + /* mod2 out is no meaning, since intr are generated in background */ + if ((d % s->period) == 0 && d != 0) + out = 1; + else + out = 0; + break; + case 3: + out = (d % s->period) < ((s->period + 1) >> 1); + break; + case 4: + case 5: + out = (d == s->period); + break; + } + return out; +} + +int pit_get_out(hvm_virpit *pit, int channel, s64 current_time) +{ + PITChannelState *s = &pit->channels[channel]; + return pit_get_out1(s, current_time); +} + +static __inline__ s64 missed_ticks(PITChannelState *s, s64 current_time) +{ + struct hvm_time_info *hvm_time = s->hvm_time; + /* ticks from current time(expected time) to NOW */ + int missed_ticks; + /* current_time is expected time for next intr, check if it's true + * (actimer has a TIMER_SLOP in advance) + */ + s64 missed_time = hvm_get_clock() + TIMER_SLOP - current_time; + + if (missed_time >= 0) { + missed_ticks = missed_time/(s_time_t)s->period + 1; + hvm_time->pending_intr_nr += missed_ticks; + s->next_transition_time = current_time + (missed_ticks ) * s->period; + } else + printk("HVM_PIT:missed ticks < 0 \n"); + + return s->next_transition_time; +} + +/* only rearm the actimer when return value > 0 + * -2: init state + * -1: the mode has expired + * 0: current VCPU is not running + * >0: the next fired time + */ +s64 pit_get_next_transition_time(PITChannelState *s, + s64 current_time) +{ + s64 d, next_time, base; + int period2; + struct hvm_time_info *hvm_time = s->hvm_time; + + d = current_time - s->count_load_time; + switch(s->mode) { + default: + case 0: + case 1: + if (d < s->period) + next_time = s->period; + else + return -1; + break; + case 2: + if (test_bit(_VCPUF_running, &(hvm_time->vcpu->vcpu_flags)) ) + next_time = missed_ticks(s, current_time); + else + return 0; + break; + case 3: + base = (d / s->period) * s->period; + period2 = ((s->period + 1) >> 1); + if ((d - base) < period2) + next_time = base + period2; + else + next_time = base + s->period; + break; + case 4: + case 5: + if (d < s->period) + next_time = s->period; + else if (d == s->period) + next_time = s->period + 1; + else + return -1; + break; + case 0xff: + return -2; /* for init state */ + break; + } + /* XXX: better solution: use a clock at PIT_FREQ Hz */ + if (next_time <= current_time){ +#ifdef DEBUG_PIT + printk("HVM_PIT:next_time <= current_time. next=0x%llx, current=0x%llx!\n",next_time, current_time); +#endif + next_time = current_time + 1; + } + return next_time; +} + +/* val must be 0 or 1 */ +void pit_set_gate(hvm_virpit *pit, int channel, int val) +{ + PITChannelState *s = &pit->channels[channel]; + + switch(s->mode) { + default: + case 0: + case 4: + /* XXX: just disable/enable counting */ + break; + case 1: + case 5: + if (s->gate < val) { + /* restart counting on rising edge */ + s->count_load_time = hvm_get_clock(); + pit_irq_timer_update(s, s->count_load_time); + } + break; + case 2: + case 3: + if (s->gate < val) { + /* restart counting on rising edge */ + s->count_load_time = hvm_get_clock(); + pit_irq_timer_update(s, s->count_load_time); + } + /* XXX: disable/enable counting */ + break; + } + s->gate = val; +} + +int pit_get_gate(hvm_virpit *pit, int channel) +{ + PITChannelState *s = &pit->channels[channel]; + return s->gate; +} + +static inline void pit_load_count(PITChannelState *s, int val) +{ + if (val == 0) + val = 0x10000; + + s->count_load_time = hvm_get_clock(); + s->count = val; + s->period = DIV_ROUND(((s->count) * NSEC_PER_SEC), PIT_FREQ); + +#ifdef DEBUG_PIT + printk("HVM_PIT: pit-load-counter, count=0x%x,period=0x%u us,mode=%d, load_time=%lld\n", + val, + s->period / 1000, + s->mode, + s->count_load_time); +#endif + + if (s->mode == HVM_PIT_ACCEL_MODE) { + if (!s->hvm_time) { + printk("HVM_PIT:guest should only set mod 2 on channel 0!\n"); + return; + } + s->hvm_time->period_cycles = (u64)s->period * cpu_khz / 1000000L; + s->hvm_time->first_injected = 0; + + if (s->period < 900000) { /* < 0.9 ms */ + printk("HVM_PIT: guest programmed too small an count: %x\n", + s->count); + s->period = 1000000; + } + } + + pit_irq_timer_update(s, s->count_load_time); +} + +/* if already latched, do not latch again */ +static void pit_latch_count(PITChannelState *s) +{ + if (!s->count_latched) { + s->latched_count = pit_get_count(s); + s->count_latched = s->rw_mode; + } +} + +static void pit_ioport_write(void *opaque, u32 addr, u32 val) +{ + hvm_virpit *pit = opaque; + int channel, access; + PITChannelState *s; + val &= 0xff; + + addr &= 3; + if (addr == 3) { + channel = val >> 6; + if (channel == 3) { + /* read back command */ + for(channel = 0; channel < 3; channel++) { + s = &pit->channels[channel]; + if (val & (2 << channel)) { + if (!(val & 0x20)) { + pit_latch_count(s); + } + if (!(val & 0x10) && !s->status_latched) { + /* status latch */ + /* XXX: add BCD and null count */ + s->status = (pit_get_out1(s, hvm_get_clock()) << 7) | + (s->rw_mode << 4) | + (s->mode << 1) | + s->bcd; + s->status_latched = 1; + } + } + } + } else { + s = &pit->channels[channel]; + access = (val >> 4) & 3; + if (access == 0) { + pit_latch_count(s); + } else { + s->rw_mode = access; + s->read_state = access; + s->write_state = access; + + s->mode = (val >> 1) & 7; + s->bcd = val & 1; + /* XXX: update irq timer ? */ + } + } + } else { + s = &pit->channels[addr]; + switch(s->write_state) { + default: + case RW_STATE_LSB: + pit_load_count(s, val); + break; + case RW_STATE_MSB: + pit_load_count(s, val << 8); + break; + case RW_STATE_WORD0: + s->write_latch = val; + s->write_state = RW_STATE_WORD1; + break; + case RW_STATE_WORD1: + pit_load_count(s, s->write_latch | (val << 8)); + s->write_state = RW_STATE_WORD0; + break; + } + } +} + +static u32 pit_ioport_read(void *opaque, u32 addr) +{ + hvm_virpit *pit = opaque; + int ret, count; + PITChannelState *s; + + addr &= 3; + s = &pit->channels[addr]; + if (s->status_latched) { + s->status_latched = 0; + ret = s->status; + } else if (s->count_latched) { + switch(s->count_latched) { + default: + case RW_STATE_LSB: + ret = s->latched_count & 0xff; + s->count_latched = 0; + break; + case RW_STATE_MSB: + ret = s->latched_count >> 8; + s->count_latched = 0; + break; + case RW_STATE_WORD0: + ret = s->latched_count & 0xff; + s->count_latched = RW_STATE_MSB; + break; + } + } else { + switch(s->read_state) { + default: + case RW_STATE_LSB: + count = pit_get_count(s); + ret = count & 0xff; + break; + case RW_STATE_MSB: + count = pit_get_count(s); + ret = (count >> 8) & 0xff; + break; + case RW_STATE_WORD0: + count = pit_get_count(s); + ret = count & 0xff; + s->read_state = RW_STATE_WORD1; + break; + case RW_STATE_WORD1: + count = pit_get_count(s); + ret = (count >> 8) & 0xff; + s->read_state = RW_STATE_WORD0; + break; + } + } + return ret; +} + +static void pit_irq_timer_update(PITChannelState *s, s64 current_time) +{ + s64 expire_time; + int irq_level; + struct vcpu *v = current; + struct hvm_virpic *pic= &v->domain->arch.hvm_domain.vpic; + + if (!s->hvm_time || s->mode == 0xff) + return; + + expire_time = pit_get_next_transition_time(s, current_time); + /* not generate intr by direct pic_set_irq in mod 2 + * XXX:mod 3 should be same as mod 2 + */ + if (s->mode != HVM_PIT_ACCEL_MODE) { + irq_level = pit_get_out1(s, current_time); + pic_set_irq(pic, s->irq, irq_level); + s->next_transition_time = expire_time; +#ifdef DEBUG_PIT + printk("HVM_PIT:irq_level=%d next_delay=%l ns\n", + irq_level, + (expire_time - current_time)); +#endif + } + + if (expire_time > 0) + set_timer(&(s->hvm_time->pit_timer), s->next_transition_time); + +} + +static void pit_irq_timer(void *data) +{ + PITChannelState *s = data; + + pit_irq_timer_update(s, s->next_transition_time); +} + +static void pit_reset(void *opaque) +{ + hvm_virpit *pit = opaque; + PITChannelState *s; + int i; + + for(i = 0;i < 3; i++) { + s = &pit->channels[i]; + s->mode = 0xff; /* the init mode */ + s->gate = (i != 2); + pit_load_count(s, 0); + } +} + +/* hvm_io_assist light-weight version, specific to PIT DM */ +static void resume_pit_io(ioreq_t *p) +{ + struct cpu_user_regs *regs = guest_cpu_user_regs(); + unsigned long old_eax = regs->eax; + p->state = STATE_INVALID; + + switch(p->size) { + case 1: + regs->eax = (old_eax & 0xffffff00) | (p->u.data & 0xff); + break; + case 2: + regs->eax = (old_eax & 0xffff0000) | (p->u.data & 0xffff); + break; + case 4: + regs->eax = (p->u.data & 0xffffffff); + break; + default: + BUG(); + } +} + +/* the intercept action for PIT DM retval:0--not handled; 1--handled */ +int handle_pit_io(ioreq_t *p) +{ + struct vcpu *v = current; + struct hvm_virpit *vpit = &(v->domain->arch.hvm_domain.vpit); + + if (p->size != 1 || + p->pdata_valid || + p->type != IOREQ_TYPE_PIO){ + printk("HVM_PIT:wrong PIT IO!\n"); + return 1; + } + + if (p->dir == 0) {/* write */ + pit_ioport_write(vpit, p->addr, p->u.data); + } else if (p->dir == 1) { /* read */ + p->u.data = pit_ioport_read(vpit, p->addr); + resume_pit_io(p); + } + + /* always return 1, since PIT sit in HV now */ + return 1; +} + +static void speaker_ioport_write(void *opaque, uint32_t addr, uint32_t val) +{ + hvm_virpit *pit = opaque; + val &= 0xff; + pit->speaker_data_on = (val >> 1) & 1; + pit_set_gate(pit, 2, val & 1); +} + +static uint32_t speaker_ioport_read(void *opaque, uint32_t addr) +{ + int out; + hvm_virpit *pit = opaque; + out = pit_get_out(pit, 2, hvm_get_clock()); + pit->dummy_refresh_clock ^= 1; + + return (pit->speaker_data_on << 1) | pit_get_gate(pit, 2) | (out << 5) | + (pit->dummy_refresh_clock << 4); +} + +int handle_speaker_io(ioreq_t *p) +{ + struct vcpu *v = current; + struct hvm_virpit *vpit = &(v->domain->arch.hvm_domain.vpit); + + if (p->size != 1 || + p->pdata_valid || + p->type != IOREQ_TYPE_PIO){ + printk("HVM_SPEAKER:wrong SPEAKER IO!\n"); + return 1; + } + + if (p->dir == 0) {/* write */ + speaker_ioport_write(vpit, p->addr, p->u.data); + } else if (p->dir == 1) {/* read */ + p->u.data = speaker_ioport_read(vpit, p->addr); + resume_pit_io(p); + } + + return 1; +} + +/* pick up missed timer ticks at deactive time */ +void pickup_deactive_ticks(struct hvm_virpit *vpit) +{ + s64 next_time; + PITChannelState *s = &(vpit->channels[0]); + if ( !active_timer(&(vpit->time_info.pit_timer)) ) { + next_time = pit_get_next_transition_time(s, s->next_transition_time); + if (next_time > 0) + set_timer(&(s->hvm_time->pit_timer), s->next_transition_time); + else { + printk("HVM_PIT:not set_timer before resume next_time=%lld!\n", next_time); + next_time = s->next_transition_time; + } + } +} + +void pit_init(struct hvm_virpit *pit, struct vcpu *v) +{ + PITChannelState *s; + struct hvm_time_info *hvm_time; + + s = &pit->channels[0]; + /* the timer 0 is connected to an IRQ */ + s->irq = 0; + /* channel 0 need access the related time info for intr injection */ + hvm_time = s->hvm_time = &pit->time_info; + hvm_time->vcpu = v; + + init_timer(&(hvm_time->pit_timer), pit_irq_timer, s, v->processor); + + register_portio_handler(PIT_BASE, 4, handle_pit_io); + + /* register the speaker port */ + register_portio_handler(0x61, 1, handle_speaker_io); + + pit_reset(pit); + + return; + +}