WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

[Xen-changelog] Sync PIT device model with latest qemu and move it to hy

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] Sync PIT device model with latest qemu and move it to hypervisor.
From: Xen patchbot -unstable <patchbot-unstable@xxxxxxxxxxxxxxxxxxx>
Date: Fri, 21 Apr 2006 16:42:08 +0000
Delivery-date: Fri, 21 Apr 2006 09:45:28 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# HG changeset patch
# User kaf24@xxxxxxxxxxxxxxxxxxxx
# Node ID 5765497cf75e7b519ccbc255b4657d854907e2db
# Parent  72f9c751d3ea1f17ff513cd7fc2cbe671a9af7c9
Sync PIT device model with latest qemu and move it to hypervisor.
Signed-off-by: Edwin Zhai <edwin.zhai@xxxxxxxxx>

diff -r 72f9c751d3ea -r 5765497cf75e tools/ioemu/hw/pc.c
--- a/tools/ioemu/hw/pc.c       Wed Apr 19 18:32:20 2006 +0100
+++ b/tools/ioemu/hw/pc.c       Wed Apr 19 18:38:14 2006 +0100
@@ -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 72f9c751d3ea -r 5765497cf75e tools/ioemu/target-i386-dm/Makefile
--- a/tools/ioemu/target-i386-dm/Makefile       Wed Apr 19 18:32:20 2006 +0100
+++ b/tools/ioemu/target-i386-dm/Makefile       Wed Apr 19 18:38:14 2006 +0100
@@ -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 72f9c751d3ea -r 5765497cf75e xen/arch/x86/hvm/Makefile
--- a/xen/arch/x86/hvm/Makefile Wed Apr 19 18:32:20 2006 +0100
+++ b/xen/arch/x86/hvm/Makefile Wed Apr 19 18:38:14 2006 +0100
@@ -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 72f9c751d3ea -r 5765497cf75e xen/arch/x86/hvm/hvm.c
--- a/xen/arch/x86/hvm/hvm.c    Wed Apr 19 18:32:20 2006 +0100
+++ b/xen/arch/x86/hvm/hvm.c    Wed Apr 19 18:38:14 2006 +0100
@@ -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 72f9c751d3ea -r 5765497cf75e xen/arch/x86/hvm/intercept.c
--- a/xen/arch/x86/hvm/intercept.c      Wed Apr 19 18:32:20 2006 +0100
+++ b/xen/arch/x86/hvm/intercept.c      Wed Apr 19 18:38:14 2006 +0100
@@ -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 72f9c751d3ea -r 5765497cf75e xen/arch/x86/hvm/io.c
--- a/xen/arch/x86/hvm/io.c     Wed Apr 19 18:32:20 2006 +0100
+++ b/xen/arch/x86/hvm/io.c     Wed Apr 19 18:38:14 2006 +0100
@@ -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 72f9c751d3ea -r 5765497cf75e xen/arch/x86/hvm/svm/intr.c
--- a/xen/arch/x86/hvm/svm/intr.c       Wed Apr 19 18:32:20 2006 +0100
+++ b/xen/arch/x86/hvm/svm/intr.c       Wed Apr 19 18:38:14 2006 +0100
@@ -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 72f9c751d3ea -r 5765497cf75e xen/arch/x86/hvm/svm/svm.c
--- a/xen/arch/x86/hvm/svm/svm.c        Wed Apr 19 18:32:20 2006 +0100
+++ b/xen/arch/x86/hvm/svm/svm.c        Wed Apr 19 18:38:14 2006 +0100
@@ -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 72f9c751d3ea -r 5765497cf75e xen/arch/x86/hvm/svm/vmcb.c
--- a/xen/arch/x86/hvm/svm/vmcb.c       Wed Apr 19 18:32:20 2006 +0100
+++ b/xen/arch/x86/hvm/svm/vmcb.c       Wed Apr 19 18:38:14 2006 +0100
@@ -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 72f9c751d3ea -r 5765497cf75e xen/arch/x86/hvm/vmx/io.c
--- a/xen/arch/x86/hvm/vmx/io.c Wed Apr 19 18:32:20 2006 +0100
+++ b/xen/arch/x86/hvm/vmx/io.c Wed Apr 19 18:38:14 2006 +0100
@@ -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 72f9c751d3ea -r 5765497cf75e xen/arch/x86/hvm/vmx/vmx.c
--- a/xen/arch/x86/hvm/vmx/vmx.c        Wed Apr 19 18:32:20 2006 +0100
+++ b/xen/arch/x86/hvm/vmx/vmx.c        Wed Apr 19 18:38:14 2006 +0100
@@ -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 72f9c751d3ea -r 5765497cf75e xen/include/asm-x86/hvm/vpit.h
--- a/xen/include/asm-x86/hvm/vpit.h    Wed Apr 19 18:32:20 2006 +0100
+++ b/xen/include/asm-x86/hvm/vpit.h    Wed Apr 19 18:38:14 2006 +0100
@@ -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 72f9c751d3ea -r 5765497cf75e xen/arch/x86/hvm/i8254.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/arch/x86/hvm/i8254.c  Wed Apr 19 18:38:14 2006 +0100
@@ -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 <edwin.zhai@xxxxxxxxx>
+ * Ported to xen:
+ * use actimer for intr generation;
+ * move speaker io access to hypervisor;
+ * use new method for counter/intrs calculation
+ */
+
+#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/vpit.h>
+#include <asm/current.h>
+
+/*#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;
+
+}

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] Sync PIT device model with latest qemu and move it to hypervisor., Xen patchbot -unstable <=