[xen master] x86: PIT emulation is common to both PV and HVM

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

[xen master] x86: PIT emulation is common to both PV and HVM

patchbot
commit 833a81b439912498e2f554560e296eb6abcf3de7
Author:     Wei Liu <[hidden email]>
AuthorDate: Tue Sep 4 17:15:22 2018 +0100
Commit:     Wei Liu <[hidden email]>
CommitDate: Thu Sep 6 16:54:38 2018 +0100

    x86: PIT emulation is common to both PV and HVM
   
    Move the file to x86 common code and change its name to emul-i8254.c.
   
    Put HVM only code under CONFIG_HVM or is_hvm_domain.
   
    Signed-off-by: Wei Liu <[hidden email]>
    Acked-by: Jan Beulich <[hidden email]>
---
 xen/arch/x86/Makefile     |   1 +
 xen/arch/x86/emul-i8254.c | 605 ++++++++++++++++++++++++++++++++++++++++++++++
 xen/arch/x86/hvm/Makefile |   1 -
 xen/arch/x86/hvm/i8254.c  | 597 ---------------------------------------------
 4 files changed, 606 insertions(+), 598 deletions(-)

diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile
index 2f2ad3adfd..162b0b94c0 100644
--- a/xen/arch/x86/Makefile
+++ b/xen/arch/x86/Makefile
@@ -27,6 +27,7 @@ obj-y += domain.o
 obj-bin-y += dom0_build.init.o
 obj-y += domain_page.o
 obj-y += e820.o
+obj-y += emul-i8254.o
 obj-y += extable.o
 obj-y += flushtlb.o
 obj-$(CONFIG_CRASH_DEBUG) += gdbstub.o
diff --git a/xen/arch/x86/emul-i8254.c b/xen/arch/x86/emul-i8254.c
new file mode 100644
index 0000000000..7f1ded2623
--- /dev/null
+++ b/xen/arch/x86/emul-i8254.c
@@ -0,0 +1,605 @@
+/*
+ * QEMU 8253/8254 interval timer emulation
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ * Copyright (c) 2006 Intel Corperation
+ * Copyright (c) 2007 Keir Fraser, XenSource Inc.
+ *
+ * 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.
+ */
+
+#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 <xen/trace.h>
+#include <asm/time.h>
+#include <asm/hvm/hvm.h>
+#include <asm/hvm/io.h>
+#include <asm/hvm/support.h>
+#include <asm/hvm/vpt.h>
+#include <asm/current.h>
+
+#define domain_vpit(x) (&(x)->arch.vpit)
+#define vcpu_vpit(x)   (domain_vpit((x)->domain))
+#define vpit_domain(x) (container_of((x), struct domain, arch.vpit))
+#define vpit_vcpu(x)   (pt_global_vcpu_target(vpit_domain(x)))
+
+#define RW_STATE_LSB 1
+#define RW_STATE_MSB 2
+#define RW_STATE_WORD0 3
+#define RW_STATE_WORD1 4
+
+static int handle_pit_io(
+    int dir, unsigned int port, unsigned int bytes, uint32_t *val);
+static int handle_speaker_io(
+    int dir, unsigned int port, unsigned int bytes, uint32_t *val);
+
+#define get_guest_time(v) \
+   (is_hvm_vcpu(v) ? hvm_get_guest_time(v) : (u64)get_s_time())
+
+static int pit_get_count(PITState *pit, int channel)
+{
+    uint64_t d;
+    int  counter;
+    struct hvm_hw_pit_channel *c = &pit->hw.channels[channel];
+    struct vcpu *v = vpit_vcpu(pit);
+
+    ASSERT(spin_is_locked(&pit->lock));
+
+    d = muldiv64(get_guest_time(v) - pit->count_load_time[channel],
+                 PIT_FREQ, SYSTEM_TIME_HZ);
+
+    switch ( c->mode )
+    {
+    case 0:
+    case 1:
+    case 4:
+    case 5:
+        counter = (c->count - d) & 0xffff;
+        break;
+    case 3:
+        /* XXX: may be incorrect for odd counts */
+        counter = c->count - ((2 * d) % c->count);
+        break;
+    default:
+        counter = c->count - (d % c->count);
+        break;
+    }
+    return counter;
+}
+
+static int pit_get_out(PITState *pit, int channel)
+{
+    struct hvm_hw_pit_channel *s = &pit->hw.channels[channel];
+    uint64_t d;
+    int out;
+    struct vcpu *v = vpit_vcpu(pit);
+
+    ASSERT(spin_is_locked(&pit->lock));
+
+    d = muldiv64(get_guest_time(v) - pit->count_load_time[channel],
+                 PIT_FREQ, SYSTEM_TIME_HZ);
+
+    switch ( s->mode )
+    {
+    default:
+    case 0:
+        out = (d >= s->count);
+        break;
+    case 1:
+        out = (d < s->count);
+        break;
+    case 2:
+        out = (((d % s->count) == 0) && (d != 0));
+        break;
+    case 3:
+        out = ((d % s->count) < ((s->count + 1) >> 1));
+        break;
+    case 4:
+    case 5:
+        out = (d == s->count);
+        break;
+    }
+
+    return out;
+}
+
+static void pit_set_gate(PITState *pit, int channel, int val)
+{
+    struct hvm_hw_pit_channel *s = &pit->hw.channels[channel];
+    struct vcpu *v = vpit_vcpu(pit);
+
+    ASSERT(spin_is_locked(&pit->lock));
+
+    switch ( s->mode )
+    {
+    default:
+    case 0:
+    case 4:
+        /* XXX: just disable/enable counting */
+        break;
+    case 1:
+    case 5:
+    case 2:
+    case 3:
+        /* Restart counting on rising edge. */
+        if ( s->gate < val )
+            pit->count_load_time[channel] = get_guest_time(v);
+        break;
+    }
+
+    s->gate = val;
+}
+
+static int pit_get_gate(PITState *pit, int channel)
+{
+    ASSERT(spin_is_locked(&pit->lock));
+    return pit->hw.channels[channel].gate;
+}
+
+static void pit_time_fired(struct vcpu *v, void *priv)
+{
+    uint64_t *count_load_time = priv;
+    TRACE_0D(TRC_HVM_EMUL_PIT_TIMER_CB);
+    *count_load_time = get_guest_time(v);
+}
+
+static void pit_load_count(PITState *pit, int channel, int val)
+{
+    u32 period;
+    struct hvm_hw_pit_channel *s = &pit->hw.channels[channel];
+    struct vcpu *v = vpit_vcpu(pit);
+
+    ASSERT(spin_is_locked(&pit->lock));
+
+    if ( val == 0 )
+        val = 0x10000;
+
+    if ( v == NULL )
+        pit->count_load_time[channel] = 0;
+    else
+        pit->count_load_time[channel] = get_guest_time(v);
+    s->count = val;
+    period = DIV_ROUND(val * SYSTEM_TIME_HZ, PIT_FREQ);
+
+    if ( (v == NULL) || !is_hvm_vcpu(v) || (channel != 0) )
+        return;
+
+    switch ( s->mode )
+    {
+    case 2:
+    case 3:
+        /* Periodic timer. */
+        TRACE_2D(TRC_HVM_EMUL_PIT_START_TIMER, period, period);
+        create_periodic_time(v, &pit->pt0, period, period, 0, pit_time_fired,
+                             &pit->count_load_time[channel], false);
+        break;
+    case 1:
+    case 4:
+        /* One-shot timer. */
+        TRACE_2D(TRC_HVM_EMUL_PIT_START_TIMER, period, 0);
+        create_periodic_time(v, &pit->pt0, period, 0, 0, pit_time_fired,
+                             &pit->count_load_time[channel], false);
+        break;
+    default:
+        TRACE_0D(TRC_HVM_EMUL_PIT_STOP_TIMER);
+        destroy_periodic_time(&pit->pt0);
+        break;
+    }
+}
+
+static void pit_latch_count(PITState *pit, int channel)
+{
+    struct hvm_hw_pit_channel *c = &pit->hw.channels[channel];
+
+    ASSERT(spin_is_locked(&pit->lock));
+
+    if ( !c->count_latched )
+    {
+        c->latched_count = pit_get_count(pit, channel);
+        c->count_latched = c->rw_mode;
+    }
+}
+
+static void pit_latch_status(PITState *pit, int channel)
+{
+    struct hvm_hw_pit_channel *c = &pit->hw.channels[channel];
+
+    ASSERT(spin_is_locked(&pit->lock));
+
+    if ( !c->status_latched )
+    {
+        /* TODO: Return NULL COUNT (bit 6). */
+        c->status = ((pit_get_out(pit, channel) << 7) |
+                     (c->rw_mode << 4) |
+                     (c->mode << 1) |
+                     c->bcd);
+        c->status_latched = 1;
+    }
+}
+
+static void pit_ioport_write(struct PITState *pit, uint32_t addr, uint32_t val)
+{
+    int channel, access;
+    struct hvm_hw_pit_channel *s;
+
+    val  &= 0xff;
+    addr &= 3;
+
+    spin_lock(&pit->lock);
+
+    if ( addr == 3 )
+    {
+        channel = val >> 6;
+        if ( channel == 3 )
+        {
+            /* Read-Back Command. */
+            for ( channel = 0; channel < 3; channel++ )
+            {
+                s = &pit->hw.channels[channel];
+                if ( val & (2 << channel) )
+                {
+                    if ( !(val & 0x20) )
+                        pit_latch_count(pit, channel);
+                    if ( !(val & 0x10) )
+                        pit_latch_status(pit, channel);
+                }
+            }
+        }
+        else
+        {
+            /* Select Counter <channel>. */
+            s = &pit->hw.channels[channel];
+            access = (val >> 4) & 3;
+            if ( access == 0 )
+            {
+                pit_latch_count(pit, channel);
+            }
+            else
+            {
+                s->rw_mode = access;
+                s->read_state = access;
+                s->write_state = access;
+                s->mode = (val >> 1) & 7;
+                if ( s->mode > 5 )
+                    s->mode -= 4;
+                s->bcd = val & 1;
+                /* XXX: update irq timer ? */
+            }
+        }
+    }
+    else
+    {
+        /* Write Count. */
+        s = &pit->hw.channels[addr];
+        switch ( s->write_state )
+        {
+        default:
+        case RW_STATE_LSB:
+            pit_load_count(pit, addr, val);
+            break;
+        case RW_STATE_MSB:
+            pit_load_count(pit, addr, 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(pit, addr, s->write_latch | (val << 8));
+            s->write_state = RW_STATE_WORD0;
+            break;
+        }
+    }
+
+    spin_unlock(&pit->lock);
+}
+
+static uint32_t pit_ioport_read(struct PITState *pit, uint32_t addr)
+{
+    int ret, count;
+    struct hvm_hw_pit_channel *s;
+    
+    addr &= 3;
+    s = &pit->hw.channels[addr];
+
+    spin_lock(&pit->lock);
+
+    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(pit, addr);
+            ret = count & 0xff;
+            break;
+        case RW_STATE_MSB:
+            count = pit_get_count(pit, addr);
+            ret = (count >> 8) & 0xff;
+            break;
+        case RW_STATE_WORD0:
+            count = pit_get_count(pit, addr);
+            ret = count & 0xff;
+            s->read_state = RW_STATE_WORD1;
+            break;
+        case RW_STATE_WORD1:
+            count = pit_get_count(pit, addr);
+            ret = (count >> 8) & 0xff;
+            s->read_state = RW_STATE_WORD0;
+            break;
+        }
+    }
+
+    spin_unlock(&pit->lock);
+
+    return ret;
+}
+
+#ifdef CONFIG_HVM
+void pit_stop_channel0_irq(PITState *pit)
+{
+    if ( !has_vpit(current->domain) )
+        return;
+
+    TRACE_0D(TRC_HVM_EMUL_PIT_STOP_TIMER);
+    spin_lock(&pit->lock);
+    destroy_periodic_time(&pit->pt0);
+    spin_unlock(&pit->lock);
+}
+
+static int pit_save(struct domain *d, hvm_domain_context_t *h)
+{
+    PITState *pit = domain_vpit(d);
+    int rc;
+
+    if ( !has_vpit(d) )
+        return 0;
+
+    spin_lock(&pit->lock);
+    
+    rc = hvm_save_entry(PIT, 0, h, &pit->hw);
+
+    spin_unlock(&pit->lock);
+
+    return rc;
+}
+
+static int pit_load(struct domain *d, hvm_domain_context_t *h)
+{
+    PITState *pit = domain_vpit(d);
+    int i;
+
+    if ( !has_vpit(d) )
+        return -ENODEV;
+
+    spin_lock(&pit->lock);
+
+    if ( hvm_load_entry(PIT, h, &pit->hw) )
+    {
+        spin_unlock(&pit->lock);
+        return 1;
+    }
+    
+    /*
+     * Recreate platform timers from hardware state.  There will be some
+     * time jitter here, but the wall-clock will have jumped massively, so
+     * we hope the guest can handle it.
+     */
+    pit->pt0.last_plt_gtime = get_guest_time(d->vcpu[0]);
+    for ( i = 0; i < 3; i++ )
+        pit_load_count(pit, i, pit->hw.channels[i].count);
+
+    spin_unlock(&pit->lock);
+
+    return 0;
+}
+
+HVM_REGISTER_SAVE_RESTORE(PIT, pit_save, pit_load, 1, HVMSR_PER_DOM);
+#endif
+
+void pit_reset(struct domain *d)
+{
+    PITState *pit = domain_vpit(d);
+    struct hvm_hw_pit_channel *s;
+    int i;
+
+    if ( !has_vpit(d) )
+        return;
+
+    if ( is_hvm_domain(d) )
+    {
+        TRACE_0D(TRC_HVM_EMUL_PIT_STOP_TIMER);
+        destroy_periodic_time(&pit->pt0);
+        pit->pt0.source = PTSRC_isa;
+    }
+
+    spin_lock(&pit->lock);
+
+    for ( i = 0; i < 3; i++ )
+    {
+        s = &pit->hw.channels[i];
+        s->mode = 0xff; /* the init mode */
+        s->gate = (i != 2);
+        pit_load_count(pit, i, 0);
+    }
+
+    spin_unlock(&pit->lock);
+}
+
+void pit_init(struct domain *d, unsigned long cpu_khz)
+{
+    PITState *pit = domain_vpit(d);
+
+    if ( !has_vpit(d) )
+        return;
+
+    spin_lock_init(&pit->lock);
+
+    if ( is_hvm_domain(d) )
+    {
+        register_portio_handler(d, PIT_BASE, 4, handle_pit_io);
+        register_portio_handler(d, 0x61, 1, handle_speaker_io);
+    }
+
+    pit_reset(d);
+}
+
+void pit_deinit(struct domain *d)
+{
+    PITState *pit = domain_vpit(d);
+
+    if ( !has_vpit(d) )
+        return;
+
+    if ( is_hvm_domain(d) )
+    {
+        TRACE_0D(TRC_HVM_EMUL_PIT_STOP_TIMER);
+        destroy_periodic_time(&pit->pt0);
+    }
+}
+
+/* the intercept action for PIT DM retval:0--not handled; 1--handled */  
+static int handle_pit_io(
+    int dir, unsigned int port, unsigned int bytes, uint32_t *val)
+{
+    struct PITState *vpit = vcpu_vpit(current);
+
+    if ( bytes != 1 )
+    {
+        gdprintk(XENLOG_WARNING, "PIT bad access\n");
+        *val = ~0;
+        return X86EMUL_OKAY;
+    }
+
+    if ( dir == IOREQ_WRITE )
+    {
+        pit_ioport_write(vpit, port, *val);
+    }
+    else
+    {
+        if ( (port & 3) != 3 )
+            *val = pit_ioport_read(vpit, port);
+        else
+            gdprintk(XENLOG_WARNING, "PIT: read A1:A0=3!\n");
+    }
+
+    return X86EMUL_OKAY;
+}
+
+static void speaker_ioport_write(
+    struct PITState *pit, uint32_t addr, uint32_t val)
+{
+    pit->hw.speaker_data_on = (val >> 1) & 1;
+    pit_set_gate(pit, 2, val & 1);
+}
+
+static uint32_t speaker_ioport_read(
+    struct PITState *pit, uint32_t addr)
+{
+    /* Refresh clock toggles at about 15us. We approximate as 2^14ns. */
+    unsigned int refresh_clock = ((unsigned int)NOW() >> 14) & 1;
+    return ((pit->hw.speaker_data_on << 1) | pit_get_gate(pit, 2) |
+            (pit_get_out(pit, 2) << 5) | (refresh_clock << 4));
+}
+
+static int handle_speaker_io(
+    int dir, unsigned int port, uint32_t bytes, uint32_t *val)
+{
+    struct PITState *vpit = vcpu_vpit(current);
+
+    BUG_ON(bytes != 1);
+
+    spin_lock(&vpit->lock);
+
+    if ( dir == IOREQ_WRITE )
+        speaker_ioport_write(vpit, port, *val);
+    else
+        *val = speaker_ioport_read(vpit, port);
+
+    spin_unlock(&vpit->lock);
+
+    return X86EMUL_OKAY;
+}
+
+int pv_pit_handler(int port, int data, int write)
+{
+    ioreq_t ioreq = {
+        .size = 1,
+        .type = IOREQ_TYPE_PIO,
+        .addr = port,
+        .dir  = write ? IOREQ_WRITE : IOREQ_READ,
+        .data = data
+    };
+
+    if ( !has_vpit(current->domain) )
+        return ~0;
+
+    if ( is_hardware_domain(current->domain) && hwdom_pit_access(&ioreq) )
+    {
+        /* nothing to do */;
+    }
+    else
+    {
+        uint32_t val = data;
+        if ( port == 0x61 )
+            handle_speaker_io(ioreq.dir, port, 1, &val);
+        else
+            handle_pit_io(ioreq.dir, port, 1, &val);
+        ioreq.data = val;
+    }
+
+    return !write ? ioreq.data : 0;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/arch/x86/hvm/Makefile b/xen/arch/x86/hvm/Makefile
index 5bd38f633f..5e04bc1429 100644
--- a/xen/arch/x86/hvm/Makefile
+++ b/xen/arch/x86/hvm/Makefile
@@ -10,7 +10,6 @@ obj-y += grant_table.o
 obj-y += hpet.o
 obj-y += hvm.o
 obj-y += hypercall.o
-obj-y += i8254.o
 obj-y += intercept.o
 obj-y += io.o
 obj-y += ioreq.o
diff --git a/xen/arch/x86/hvm/i8254.c b/xen/arch/x86/hvm/i8254.c
deleted file mode 100644
index b8ec56f8d3..0000000000
--- a/xen/arch/x86/hvm/i8254.c
+++ /dev/null
@@ -1,597 +0,0 @@
-/*
- * QEMU 8253/8254 interval timer emulation
- *
- * Copyright (c) 2003-2004 Fabrice Bellard
- * Copyright (c) 2006 Intel Corperation
- * Copyright (c) 2007 Keir Fraser, XenSource Inc.
- *
- * 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.
- */
-
-#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 <xen/trace.h>
-#include <asm/time.h>
-#include <asm/hvm/hvm.h>
-#include <asm/hvm/io.h>
-#include <asm/hvm/support.h>
-#include <asm/hvm/vpt.h>
-#include <asm/current.h>
-
-#define domain_vpit(x) (&(x)->arch.vpit)
-#define vcpu_vpit(x)   (domain_vpit((x)->domain))
-#define vpit_domain(x) (container_of((x), struct domain, arch.vpit))
-#define vpit_vcpu(x)   (pt_global_vcpu_target(vpit_domain(x)))
-
-#define RW_STATE_LSB 1
-#define RW_STATE_MSB 2
-#define RW_STATE_WORD0 3
-#define RW_STATE_WORD1 4
-
-static int handle_pit_io(
-    int dir, unsigned int port, unsigned int bytes, uint32_t *val);
-static int handle_speaker_io(
-    int dir, unsigned int port, unsigned int bytes, uint32_t *val);
-
-#define get_guest_time(v) \
-   (is_hvm_vcpu(v) ? hvm_get_guest_time(v) : (u64)get_s_time())
-
-static int pit_get_count(PITState *pit, int channel)
-{
-    uint64_t d;
-    int  counter;
-    struct hvm_hw_pit_channel *c = &pit->hw.channels[channel];
-    struct vcpu *v = vpit_vcpu(pit);
-
-    ASSERT(spin_is_locked(&pit->lock));
-
-    d = muldiv64(get_guest_time(v) - pit->count_load_time[channel],
-                 PIT_FREQ, SYSTEM_TIME_HZ);
-
-    switch ( c->mode )
-    {
-    case 0:
-    case 1:
-    case 4:
-    case 5:
-        counter = (c->count - d) & 0xffff;
-        break;
-    case 3:
-        /* XXX: may be incorrect for odd counts */
-        counter = c->count - ((2 * d) % c->count);
-        break;
-    default:
-        counter = c->count - (d % c->count);
-        break;
-    }
-    return counter;
-}
-
-static int pit_get_out(PITState *pit, int channel)
-{
-    struct hvm_hw_pit_channel *s = &pit->hw.channels[channel];
-    uint64_t d;
-    int out;
-    struct vcpu *v = vpit_vcpu(pit);
-
-    ASSERT(spin_is_locked(&pit->lock));
-
-    d = muldiv64(get_guest_time(v) - pit->count_load_time[channel],
-                 PIT_FREQ, SYSTEM_TIME_HZ);
-
-    switch ( s->mode )
-    {
-    default:
-    case 0:
-        out = (d >= s->count);
-        break;
-    case 1:
-        out = (d < s->count);
-        break;
-    case 2:
-        out = (((d % s->count) == 0) && (d != 0));
-        break;
-    case 3:
-        out = ((d % s->count) < ((s->count + 1) >> 1));
-        break;
-    case 4:
-    case 5:
-        out = (d == s->count);
-        break;
-    }
-
-    return out;
-}
-
-static void pit_set_gate(PITState *pit, int channel, int val)
-{
-    struct hvm_hw_pit_channel *s = &pit->hw.channels[channel];
-    struct vcpu *v = vpit_vcpu(pit);
-
-    ASSERT(spin_is_locked(&pit->lock));
-
-    switch ( s->mode )
-    {
-    default:
-    case 0:
-    case 4:
-        /* XXX: just disable/enable counting */
-        break;
-    case 1:
-    case 5:
-    case 2:
-    case 3:
-        /* Restart counting on rising edge. */
-        if ( s->gate < val )
-            pit->count_load_time[channel] = get_guest_time(v);
-        break;
-    }
-
-    s->gate = val;
-}
-
-static int pit_get_gate(PITState *pit, int channel)
-{
-    ASSERT(spin_is_locked(&pit->lock));
-    return pit->hw.channels[channel].gate;
-}
-
-static void pit_time_fired(struct vcpu *v, void *priv)
-{
-    uint64_t *count_load_time = priv;
-    TRACE_0D(TRC_HVM_EMUL_PIT_TIMER_CB);
-    *count_load_time = get_guest_time(v);
-}
-
-static void pit_load_count(PITState *pit, int channel, int val)
-{
-    u32 period;
-    struct hvm_hw_pit_channel *s = &pit->hw.channels[channel];
-    struct vcpu *v = vpit_vcpu(pit);
-
-    ASSERT(spin_is_locked(&pit->lock));
-
-    if ( val == 0 )
-        val = 0x10000;
-
-    if ( v == NULL )
-        pit->count_load_time[channel] = 0;
-    else
-        pit->count_load_time[channel] = get_guest_time(v);
-    s->count = val;
-    period = DIV_ROUND(val * SYSTEM_TIME_HZ, PIT_FREQ);
-
-    if ( (v == NULL) || !is_hvm_vcpu(v) || (channel != 0) )
-        return;
-
-    switch ( s->mode )
-    {
-    case 2:
-    case 3:
-        /* Periodic timer. */
-        TRACE_2D(TRC_HVM_EMUL_PIT_START_TIMER, period, period);
-        create_periodic_time(v, &pit->pt0, period, period, 0, pit_time_fired,
-                             &pit->count_load_time[channel], false);
-        break;
-    case 1:
-    case 4:
-        /* One-shot timer. */
-        TRACE_2D(TRC_HVM_EMUL_PIT_START_TIMER, period, 0);
-        create_periodic_time(v, &pit->pt0, period, 0, 0, pit_time_fired,
-                             &pit->count_load_time[channel], false);
-        break;
-    default:
-        TRACE_0D(TRC_HVM_EMUL_PIT_STOP_TIMER);
-        destroy_periodic_time(&pit->pt0);
-        break;
-    }
-}
-
-static void pit_latch_count(PITState *pit, int channel)
-{
-    struct hvm_hw_pit_channel *c = &pit->hw.channels[channel];
-
-    ASSERT(spin_is_locked(&pit->lock));
-
-    if ( !c->count_latched )
-    {
-        c->latched_count = pit_get_count(pit, channel);
-        c->count_latched = c->rw_mode;
-    }
-}
-
-static void pit_latch_status(PITState *pit, int channel)
-{
-    struct hvm_hw_pit_channel *c = &pit->hw.channels[channel];
-
-    ASSERT(spin_is_locked(&pit->lock));
-
-    if ( !c->status_latched )
-    {
-        /* TODO: Return NULL COUNT (bit 6). */
-        c->status = ((pit_get_out(pit, channel) << 7) |
-                     (c->rw_mode << 4) |
-                     (c->mode << 1) |
-                     c->bcd);
-        c->status_latched = 1;
-    }
-}
-
-static void pit_ioport_write(struct PITState *pit, uint32_t addr, uint32_t val)
-{
-    int channel, access;
-    struct hvm_hw_pit_channel *s;
-
-    val  &= 0xff;
-    addr &= 3;
-
-    spin_lock(&pit->lock);
-
-    if ( addr == 3 )
-    {
-        channel = val >> 6;
-        if ( channel == 3 )
-        {
-            /* Read-Back Command. */
-            for ( channel = 0; channel < 3; channel++ )
-            {
-                s = &pit->hw.channels[channel];
-                if ( val & (2 << channel) )
-                {
-                    if ( !(val & 0x20) )
-                        pit_latch_count(pit, channel);
-                    if ( !(val & 0x10) )
-                        pit_latch_status(pit, channel);
-                }
-            }
-        }
-        else
-        {
-            /* Select Counter <channel>. */
-            s = &pit->hw.channels[channel];
-            access = (val >> 4) & 3;
-            if ( access == 0 )
-            {
-                pit_latch_count(pit, channel);
-            }
-            else
-            {
-                s->rw_mode = access;
-                s->read_state = access;
-                s->write_state = access;
-                s->mode = (val >> 1) & 7;
-                if ( s->mode > 5 )
-                    s->mode -= 4;
-                s->bcd = val & 1;
-                /* XXX: update irq timer ? */
-            }
-        }
-    }
-    else
-    {
-        /* Write Count. */
-        s = &pit->hw.channels[addr];
-        switch ( s->write_state )
-        {
-        default:
-        case RW_STATE_LSB:
-            pit_load_count(pit, addr, val);
-            break;
-        case RW_STATE_MSB:
-            pit_load_count(pit, addr, 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(pit, addr, s->write_latch | (val << 8));
-            s->write_state = RW_STATE_WORD0;
-            break;
-        }
-    }
-
-    spin_unlock(&pit->lock);
-}
-
-static uint32_t pit_ioport_read(struct PITState *pit, uint32_t addr)
-{
-    int ret, count;
-    struct hvm_hw_pit_channel *s;
-    
-    addr &= 3;
-    s = &pit->hw.channels[addr];
-
-    spin_lock(&pit->lock);
-
-    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(pit, addr);
-            ret = count & 0xff;
-            break;
-        case RW_STATE_MSB:
-            count = pit_get_count(pit, addr);
-            ret = (count >> 8) & 0xff;
-            break;
-        case RW_STATE_WORD0:
-            count = pit_get_count(pit, addr);
-            ret = count & 0xff;
-            s->read_state = RW_STATE_WORD1;
-            break;
-        case RW_STATE_WORD1:
-            count = pit_get_count(pit, addr);
-            ret = (count >> 8) & 0xff;
-            s->read_state = RW_STATE_WORD0;
-            break;
-        }
-    }
-
-    spin_unlock(&pit->lock);
-
-    return ret;
-}
-
-void pit_stop_channel0_irq(PITState *pit)
-{
-    if ( !has_vpit(current->domain) )
-        return;
-
-    TRACE_0D(TRC_HVM_EMUL_PIT_STOP_TIMER);
-    spin_lock(&pit->lock);
-    destroy_periodic_time(&pit->pt0);
-    spin_unlock(&pit->lock);
-}
-
-static int pit_save(struct domain *d, hvm_domain_context_t *h)
-{
-    PITState *pit = domain_vpit(d);
-    int rc;
-
-    if ( !has_vpit(d) )
-        return 0;
-
-    spin_lock(&pit->lock);
-    
-    rc = hvm_save_entry(PIT, 0, h, &pit->hw);
-
-    spin_unlock(&pit->lock);
-
-    return rc;
-}
-
-static int pit_load(struct domain *d, hvm_domain_context_t *h)
-{
-    PITState *pit = domain_vpit(d);
-    int i;
-
-    if ( !has_vpit(d) )
-        return -ENODEV;
-
-    spin_lock(&pit->lock);
-
-    if ( hvm_load_entry(PIT, h, &pit->hw) )
-    {
-        spin_unlock(&pit->lock);
-        return 1;
-    }
-    
-    /*
-     * Recreate platform timers from hardware state.  There will be some
-     * time jitter here, but the wall-clock will have jumped massively, so
-     * we hope the guest can handle it.
-     */
-    pit->pt0.last_plt_gtime = get_guest_time(d->vcpu[0]);
-    for ( i = 0; i < 3; i++ )
-        pit_load_count(pit, i, pit->hw.channels[i].count);
-
-    spin_unlock(&pit->lock);
-
-    return 0;
-}
-
-HVM_REGISTER_SAVE_RESTORE(PIT, pit_save, pit_load, 1, HVMSR_PER_DOM);
-
-void pit_reset(struct domain *d)
-{
-    PITState *pit = domain_vpit(d);
-    struct hvm_hw_pit_channel *s;
-    int i;
-
-    if ( !has_vpit(d) )
-        return;
-
-    TRACE_0D(TRC_HVM_EMUL_PIT_STOP_TIMER);
-    destroy_periodic_time(&pit->pt0);
-    pit->pt0.source = PTSRC_isa;
-
-    spin_lock(&pit->lock);
-
-    for ( i = 0; i < 3; i++ )
-    {
-        s = &pit->hw.channels[i];
-        s->mode = 0xff; /* the init mode */
-        s->gate = (i != 2);
-        pit_load_count(pit, i, 0);
-    }
-
-    spin_unlock(&pit->lock);
-}
-
-void pit_init(struct domain *d, unsigned long cpu_khz)
-{
-    PITState *pit = domain_vpit(d);
-
-    if ( !has_vpit(d) )
-        return;
-
-    spin_lock_init(&pit->lock);
-
-    if ( is_hvm_domain(d) )
-    {
-        register_portio_handler(d, PIT_BASE, 4, handle_pit_io);
-        register_portio_handler(d, 0x61, 1, handle_speaker_io);
-    }
-
-    pit_reset(d);
-}
-
-void pit_deinit(struct domain *d)
-{
-    PITState *pit = domain_vpit(d);
-
-    if ( !has_vpit(d) )
-        return;
-
-    TRACE_0D(TRC_HVM_EMUL_PIT_STOP_TIMER);
-    destroy_periodic_time(&pit->pt0);
-}
-
-/* the intercept action for PIT DM retval:0--not handled; 1--handled */  
-static int handle_pit_io(
-    int dir, unsigned int port, unsigned int bytes, uint32_t *val)
-{
-    struct PITState *vpit = vcpu_vpit(current);
-
-    if ( bytes != 1 )
-    {
-        gdprintk(XENLOG_WARNING, "PIT bad access\n");
-        *val = ~0;
-        return X86EMUL_OKAY;
-    }
-
-    if ( dir == IOREQ_WRITE )
-    {
-        pit_ioport_write(vpit, port, *val);
-    }
-    else
-    {
-        if ( (port & 3) != 3 )
-            *val = pit_ioport_read(vpit, port);
-        else
-            gdprintk(XENLOG_WARNING, "PIT: read A1:A0=3!\n");
-    }
-
-    return X86EMUL_OKAY;
-}
-
-static void speaker_ioport_write(
-    struct PITState *pit, uint32_t addr, uint32_t val)
-{
-    pit->hw.speaker_data_on = (val >> 1) & 1;
-    pit_set_gate(pit, 2, val & 1);
-}
-
-static uint32_t speaker_ioport_read(
-    struct PITState *pit, uint32_t addr)
-{
-    /* Refresh clock toggles at about 15us. We approximate as 2^14ns. */
-    unsigned int refresh_clock = ((unsigned int)NOW() >> 14) & 1;
-    return ((pit->hw.speaker_data_on << 1) | pit_get_gate(pit, 2) |
-            (pit_get_out(pit, 2) << 5) | (refresh_clock << 4));
-}
-
-static int handle_speaker_io(
-    int dir, unsigned int port, uint32_t bytes, uint32_t *val)
-{
-    struct PITState *vpit = vcpu_vpit(current);
-
-    BUG_ON(bytes != 1);
-
-    spin_lock(&vpit->lock);
-
-    if ( dir == IOREQ_WRITE )
-        speaker_ioport_write(vpit, port, *val);
-    else
-        *val = speaker_ioport_read(vpit, port);
-
-    spin_unlock(&vpit->lock);
-
-    return X86EMUL_OKAY;
-}
-
-int pv_pit_handler(int port, int data, int write)
-{
-    ioreq_t ioreq = {
-        .size = 1,
-        .type = IOREQ_TYPE_PIO,
-        .addr = port,
-        .dir  = write ? IOREQ_WRITE : IOREQ_READ,
-        .data = data
-    };
-
-    if ( !has_vpit(current->domain) )
-        return ~0;
-
-    if ( is_hardware_domain(current->domain) && hwdom_pit_access(&ioreq) )
-    {
-        /* nothing to do */;
-    }
-    else
-    {
-        uint32_t val = data;
-        if ( port == 0x61 )
-            handle_speaker_io(ioreq.dir, port, 1, &val);
-        else
-            handle_pit_io(ioreq.dir, port, 1, &val);
-        ioreq.data = val;
-    }
-
-    return !write ? ioreq.data : 0;
-}
-
-/*
- * Local variables:
- * mode: C
- * c-file-style: "BSD"
- * c-basic-offset: 4
- * indent-tabs-mode: nil
- * End:
- */
--
generated by git-patchbot for /home/xen/git/xen.git#master

_______________________________________________
Xen-changelog mailing list
[hidden email]
https://lists.xenproject.org/xen-changelog