[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-unstable] [XEN] Provide PV guests with emulated PIT.



# HG changeset patch
# User kfraser@xxxxxxxxxxxxxxxxxxxxx
# Node ID cd89771ba5508e9d1d8c76448c11dc9809e1e70d
# Parent  afc6b5a60866d79d86af934515cf13f847acf6fc
[XEN] Provide PV guests with emulated PIT.
This is needed for some video-controller BIOSes which use PIT channel
2 for delay loops.
Signed-off-by: Xiaowei Yang <xiaowei.yang@xxxxxxxxx>
---
 xen/arch/x86/domain.c         |    4 ++++
 xen/arch/x86/hvm/hvm.c        |    1 -
 xen/arch/x86/hvm/i8254.c      |   41 ++++++++++++++++++++++++++++++++---------
 xen/arch/x86/traps.c          |   28 +++++++++++++++-------------
 xen/include/asm-x86/hvm/vpt.h |    2 +-
 5 files changed, 52 insertions(+), 24 deletions(-)

diff -r afc6b5a60866 -r cd89771ba550 xen/arch/x86/domain.c
--- a/xen/arch/x86/domain.c     Thu Dec 14 16:00:31 2006 +0000
+++ b/xen/arch/x86/domain.c     Thu Dec 14 16:27:10 2006 +0000
@@ -136,6 +136,10 @@ int vcpu_initialise(struct vcpu *v)
 
     pae_l3_cache_init(&v->arch.pae_l3_cache);
 
+    /* This should move to arch_domain_create(). */
+    if ( !is_idle_domain(d) && (v->vcpu_id == 0) )
+        pit_init(v, cpu_khz);
+
     if ( is_hvm_domain(d) )
     {
         if ( (rc = hvm_vcpu_initialise(v)) != 0 )
diff -r afc6b5a60866 -r cd89771ba550 xen/arch/x86/hvm/hvm.c
--- a/xen/arch/x86/hvm/hvm.c    Thu Dec 14 16:00:31 2006 +0000
+++ b/xen/arch/x86/hvm/hvm.c    Thu Dec 14 16:27:10 2006 +0000
@@ -222,7 +222,6 @@ int hvm_vcpu_initialise(struct vcpu *v)
 
     init_timer(&platform->pl_time.periodic_tm.timer,
                pt_timer_fn, v, v->processor);
-    pit_init(v, cpu_khz);
     rtc_init(v, RTC_PORT(0), RTC_IRQ);
     pmtimer_init(v, ACPI_PM_TMR_BLK_ADDRESS);
 
diff -r afc6b5a60866 -r cd89771ba550 xen/arch/x86/hvm/i8254.c
--- a/xen/arch/x86/hvm/i8254.c  Thu Dec 14 16:00:31 2006 +0000
+++ b/xen/arch/x86/hvm/i8254.c  Thu Dec 14 16:27:10 2006 +0000
@@ -184,12 +184,18 @@ void pit_time_fired(struct vcpu *v, void
 
 static inline void pit_load_count(PITChannelState *s, int val)
 {
-    u32   period;
+    u32 period;
+    PITChannelState *ch0 =
+        &current->domain->arch.hvm_domain.pl_time.vpit.channels[0];
+
     if (val == 0)
         val = 0x10000;
     s->count_load_time = hvm_get_clock(s->vcpu);
     s->count = val;
     period = DIV_ROUND((val * 1000000000ULL), PIT_FREQ);
+
+    if (s != ch0)
+        return;
 
 #ifdef DEBUG_PIT
     printk("HVM_PIT: pit-load-counter(%p), count=0x%x, period=%uns mode=%d, 
load_time=%lld\n",
@@ -419,13 +425,12 @@ static void speaker_ioport_write(void *o
 
 static uint32_t speaker_ioport_read(void *opaque, uint32_t addr)
 {
-    int out;
-    PITState *pit = opaque;
-    out = pit_get_out(pit, 2, hvm_get_clock(pit->channels[2].vcpu));
-    pit->dummy_refresh_clock ^= 1;
-
-    return (pit->speaker_data_on << 1) | pit_get_gate(pit, 2) | (out << 5) |
-      (pit->dummy_refresh_clock << 4);
+    PITState *pit = opaque;
+    int out = pit_get_out(pit, 2, hvm_get_clock(pit->channels[2].vcpu));
+    /* Refresh clock toggles at about 15us. We approximate as 2^14ns. */
+    unsigned int refresh_clock = ((unsigned int)NOW() >> 14) & 1;
+    return ((pit->speaker_data_on << 1) | pit_get_gate(pit, 2) |
+            (out << 5) | refresh_clock << 4);
 }
 
 static int handle_speaker_io(ioreq_t *p)
@@ -439,7 +444,7 @@ static int handle_speaker_io(ioreq_t *p)
         printk("HVM_SPEAKER:wrong SPEAKER IO!\n");
         return 1;
     }
-    
+
     if (p->dir == 0) {/* write */
         speaker_ioport_write(vpit, p->addr, p->data);
     } else if (p->dir == 1) {/* read */
@@ -448,3 +453,21 @@ static int handle_speaker_io(ioreq_t *p)
 
     return 1;
 }
+
+int pv_pit_handler(int port, int data, int write)
+{
+    ioreq_t ioreq = {
+        .size = 1,
+        .type = IOREQ_TYPE_PIO,
+        .addr = port,
+        .dir  = write ? 0 : 1,
+        .data = write ? data : 0,
+    };
+
+    if (port == 0x61)
+        handle_speaker_io(&ioreq);
+    else
+        handle_pit_io(&ioreq);
+
+    return !write ? ioreq.data : 0;
+}
diff -r afc6b5a60866 -r cd89771ba550 xen/arch/x86/traps.c
--- a/xen/arch/x86/traps.c      Thu Dec 14 16:00:31 2006 +0000
+++ b/xen/arch/x86/traps.c      Thu Dec 14 16:27:10 2006 +0000
@@ -59,6 +59,7 @@
 #include <asm/debugger.h>
 #include <asm/msr.h>
 #include <asm/x86_emulate.h>
+#include <asm/hvm/vpt.h>
 
 /*
  * opt_nmi: one of 'ignore', 'dom0', or 'fatal'.
@@ -1035,18 +1036,7 @@ static inline int admin_io_okay(
     return ioports_access_permitted(v->domain, port, port + bytes - 1);
 }
 
-static inline int guest_inb_okay(
-    unsigned int port, struct vcpu *v, struct cpu_user_regs *regs)
-{
-    /*
-     * Allow read access to port 0x61. Bit 4 oscillates with period 30us, and
-     * so it is often used for timing loops in BIOS code. This hack can go
-     * away when we have separate read/write permission rangesets.
-     * Note that we could emulate bit 4 instead of directly reading port 0x61,
-     * but there's not really a good reason to do so.
-     */
-    return (admin_io_okay(port, 1, v, regs) || (port == 0x61));
-}
+#define guest_inb_okay(_p, _d, _r) admin_io_okay(_p, 1, _d, _r)
 #define guest_inw_okay(_p, _d, _r) admin_io_okay(_p, 2, _d, _r)
 #define guest_inl_okay(_p, _d, _r) admin_io_okay(_p, 4, _d, _r)
 #define guest_outb_okay(_p, _d, _r) admin_io_okay(_p, 1, _d, _r)
@@ -1141,7 +1131,10 @@ static int emulate_privileged_op(struct 
             switch ( op_bytes )
             {
             case 1:
-                data = (u8)(guest_inb_okay(port, v, regs) ? inb(port) : ~0);
+                /* emulate PIT counter 2 */
+                data = (u8)(guest_inb_okay(port, v, regs) ? inb(port) : 
+                       ((port == 0x42 || port == 0x43 || port == 0x61) ?
+                       pv_pit_handler(port, 0, 0) : ~0)); 
                 break;
             case 2:
                 data = (u16)(guest_inw_okay(port, v, regs) ? inw(port) : ~0);
@@ -1176,6 +1169,8 @@ static int emulate_privileged_op(struct 
             case 1:
                 if ( guest_outb_okay(port, v, regs) )
                     outb((u8)data, port);
+                else if ( port == 0x42 || port == 0x43 || port == 0x61 )
+                    pv_pit_handler(port, data, 1);
                 break;
             case 2:
                 if ( guest_outw_okay(port, v, regs) )
@@ -1240,6 +1235,11 @@ static int emulate_privileged_op(struct 
         case 1:
             if ( guest_inb_okay(port, v, regs) )
                 io_emul(regs);
+            else if ( port == 0x42 || port == 0x43 || port == 0x61 )
+            {
+                regs->eax &= ~0xffUL;
+                regs->eax |= pv_pit_handler(port, 0, 0);
+            } 
             else
                 regs->eax |= (u8)~0;
             break;
@@ -1277,6 +1277,8 @@ static int emulate_privileged_op(struct 
         case 1:
             if ( guest_outb_okay(port, v, regs) )
                 io_emul(regs);
+            else if ( port == 0x42 || port == 0x43 || port == 0x61 )
+                pv_pit_handler(port, regs->eax, 1);
             break;
         case 2:
             if ( guest_outw_okay(port, v, regs) )
diff -r afc6b5a60866 -r cd89771ba550 xen/include/asm-x86/hvm/vpt.h
--- a/xen/include/asm-x86/hvm/vpt.h     Thu Dec 14 16:00:31 2006 +0000
+++ b/xen/include/asm-x86/hvm/vpt.h     Thu Dec 14 16:27:10 2006 +0000
@@ -54,7 +54,6 @@ typedef struct PITState {
 typedef struct PITState {
     PITChannelState channels[3];
     int speaker_data_on;
-    int dummy_refresh_clock;
 } PITState;
 
 #define RTC_SIZE 14
@@ -125,6 +124,7 @@ extern struct periodic_time *create_peri
 extern struct periodic_time *create_periodic_time(
     u32 period, char irq, char one_shot, time_cb *cb, void *data);
 extern void destroy_periodic_time(struct periodic_time *pt);
+int pv_pit_handler(int port, int data, int write);
 void pit_init(struct vcpu *v, unsigned long cpu_khz);
 void rtc_init(struct vcpu *v, int base, int irq);
 void rtc_deinit(struct domain *d);

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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.