All of lore.kernel.org
 help / color / mirror / Atom feed
From: Wei Liu <wei.liu2@citrix.com>
To: xen-devel@lists.xenproject.org
Cc: Andrew Cooper <andrew.cooper3@citrix.com>,
	Wei Liu <wei.liu2@citrix.com>, Jan Beulich <jbeulich@suse.com>
Subject: [PATCH v2 19/23] x86: PIT emulation is common to both PV and HVM
Date: Sun, 26 Aug 2018 13:19:52 +0100	[thread overview]
Message-ID: <3c651e5f60a496e3e5661f60bd7e913dab2b05a0.1535285866.git-series.wei.liu2@citrix.com> (raw)
In-Reply-To: <cover.65253d1128f698146b48c4ff3bba2198f360c7b1.1535285866.git-series.wei.liu2@citrix.com>

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 <wei.liu2@citrix.com>
---
v2: move the whole file.
---
 xen/arch/x86/Makefile     |   1 +-
 xen/arch/x86/emul-i8254.c | 609 +++++++++++++++++++++++++++++++++++++++-
 xen/arch/x86/hvm/Makefile |   1 +-
 xen/arch/x86/hvm/i8254.c  | 597 +--------------------------------------
 4 files changed, 610 insertions(+), 598 deletions(-)
 create mode 100644 xen/arch/x86/emul-i8254.c
 delete mode 100644 xen/arch/x86/hvm/i8254.c

diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile
index 43f9189..c03bca6 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 0000000..f4436f8
--- /dev/null
+++ b/xen/arch/x86/emul-i8254.c
@@ -0,0 +1,609 @@
+/*
+ * 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;
+}
+
+#ifdef CONFIG_HVM
+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);
+}
+#endif
+
+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;
+
+#ifdef CONFIG_HVM
+    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;
+    }
+#endif
+}
+
+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 5bd38f6..5e04bc1 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 b8ec56f..0000000
--- 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:
- */
-- 
git-series 0.9.1

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

  parent reply	other threads:[~2018-08-26 12:28 UTC|newest]

Thread overview: 97+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-08-26 12:19 [PATCH v2 00/23] Make CONFIG_HVM work Wei Liu
2018-08-26 12:19 ` [PATCH v2 01/23] x86: change name of parameter for various invlpg functions Wei Liu
2018-08-27 13:49   ` Boris Ostrovsky
2018-08-27 13:54     ` Jan Beulich
2018-08-27 14:20   ` Jan Beulich
2018-08-30  1:26   ` Tian, Kevin
2018-09-03 13:46   ` Wei Liu
2018-09-04 13:42     ` Boris Ostrovsky
2018-08-26 12:19 ` [PATCH v2 02/23] xen: is_hvm_{domain, vcpu} should evaluate to false when !CONFIG_HVM Wei Liu
2018-08-27 14:24   ` Jan Beulich
2018-08-28  8:41     ` Wei Liu
2018-08-28 11:09       ` Julien Grall
2018-08-26 12:19 ` [PATCH v2 03/23] x86: enclose hvm_op and dm_op in CONFIG_HVM in relevant tables Wei Liu
2018-08-27 14:24   ` Jan Beulich
2018-08-26 12:19 ` [PATCH v2 04/23] x86/hvm: provide hvm_hap_supported Wei Liu
2018-08-27 14:25   ` Jan Beulich
2018-08-26 12:19 ` [PATCH v2 05/23] x86: provide stub for memory_type_changed Wei Liu
2018-08-27 14:28   ` Jan Beulich
2018-08-26 12:19 ` [PATCH v2 06/23] x86: don't call vpci function in physdev_op when !CONFIG_HAS_VPCI Wei Liu
2018-08-27 14:29   ` Jan Beulich
2018-08-28  8:45     ` Wei Liu
2018-08-28  9:08       ` Jan Beulich
2018-08-29 16:23         ` Wei Liu
2018-08-26 12:19 ` [PATCH v2 07/23] x86/vpmu: put HVM only code under CONFIG_HVM Wei Liu
2018-08-27 15:03   ` Jan Beulich
2018-08-26 12:19 ` [PATCH v2 08/23] xen/pt: io.c contains HVM only code Wei Liu
2018-08-27 15:04   ` Jan Beulich
2018-08-26 12:19 ` [PATCH v2 09/23] x86/pt: make it build with !CONFIG_HVM Wei Liu
2018-08-27 15:07   ` Jan Beulich
2018-08-30  1:29   ` Tian, Kevin
2018-08-26 12:19 ` [PATCH v2 10/23] x86/pt: split out HVM functions from vtd.c Wei Liu
2018-08-30  1:29   ` Tian, Kevin
2018-08-26 12:19 ` [PATCH v2 11/23] x86: XENMEM_resource_ioreq_server is HVM only Wei Liu
2018-08-27 15:13   ` Jan Beulich
2018-08-29 16:28     ` Wei Liu
2018-08-26 12:19 ` [PATCH v2 12/23] x86: monitor.o is currently " Wei Liu
2018-08-26 16:33   ` Razvan Cojocaru
2018-08-27 15:18   ` Jan Beulich
2018-08-27 15:23     ` Razvan Cojocaru
2018-08-29 16:42     ` Wei Liu
2018-08-29 17:43       ` Tamas K Lengyel
2018-08-29 18:09         ` Razvan Cojocaru
2018-08-30  7:14           ` Wei Liu
2018-08-26 12:19 ` [PATCH v2 13/23] x86: provide stubs, declarations and macros in hvm.h Wei Liu
2018-08-27 15:43   ` Jan Beulich
2018-09-03  9:45   ` Paul Durrant
2018-09-03  9:50     ` Wei Liu
2018-08-26 12:19 ` [PATCH v2 14/23] x86/mm: put nested p2m code under CONFIG_HVM Wei Liu
2018-08-27 15:56   ` Jan Beulich
2018-08-28  8:40     ` Wei Liu
2018-08-28  9:10       ` Jan Beulich
2018-08-26 12:19 ` [PATCH v2 15/23] x86/mm: put HVM only " Wei Liu
2018-08-26 16:39   ` Razvan Cojocaru
2018-08-27  9:03   ` Wei Liu
2018-08-28 10:41     ` Wei Liu
2018-08-28 10:53       ` Jan Beulich
2018-08-27 16:01   ` Jan Beulich
2018-08-28 10:41     ` Wei Liu
2018-08-26 12:19 ` [PATCH v2 16/23] x86/p2m/pod: make it build with !CONFIG_HVM Wei Liu
2018-08-28 10:47   ` Jan Beulich
2018-08-28 10:54     ` Wei Liu
2018-08-28 11:32       ` Jan Beulich
2018-08-26 12:19 ` [PATCH v2 17/23] x86/mm: put paging_update_nestedmode under CONFIG_HVM Wei Liu
2018-08-28 10:50   ` Jan Beulich
2018-08-30  7:42     ` Wei Liu
2018-08-30  8:35       ` Jan Beulich
2018-09-03 14:27         ` Wei Liu
2018-09-03 14:48           ` Jan Beulich
2018-08-26 12:19 ` [PATCH v2 18/23] x86/domctl: XEN_DOMCTL_debug_op is HVM only Wei Liu
2018-08-28 10:50   ` Jan Beulich
2018-08-26 12:19 ` Wei Liu [this message]
2018-08-28 11:44   ` [PATCH v2 19/23] x86: PIT emulation is common to both PV and HVM Jan Beulich
2018-08-28 13:19     ` Wei Liu
2018-08-28 14:36       ` Jan Beulich
2018-08-28 14:48         ` Wei Liu
2018-08-28 14:51           ` Andrew Cooper
2018-08-28 14:58             ` Wei Liu
2018-08-28 15:04               ` Jan Beulich
2018-08-28 15:17                 ` Wei Liu
2018-08-28 14:56           ` Wei Liu
2018-08-26 12:19 ` [PATCH v2 20/23] xen: connect guest creation with CONFIG_{HVM, PV} Wei Liu
2018-08-28 11:07   ` Julien Grall
2018-08-28 13:13     ` Wei Liu
2018-08-28 11:47   ` Jan Beulich
2018-08-28 13:15     ` Wei Liu
2018-08-26 12:19 ` [PATCH v2 21/23] x86: expose CONFIG_HVM Wei Liu
2018-08-28 11:50   ` Jan Beulich
2018-08-28 12:14     ` Andrew Cooper
2018-08-28 13:33       ` Jan Beulich
2018-08-29 16:56         ` Andrew Cooper
2018-08-30  6:21           ` Jan Beulich
2018-08-30  6:57             ` Juergen Gross
2018-08-31 20:09             ` Andrew Cooper
2018-09-03 11:35               ` Jan Beulich
2018-08-26 12:19 ` [PATCH v2 22/23] x86/pvshim: disable HVM for PV shim Wei Liu
2018-08-26 12:19 ` [PATCH v2 23/23] xen: decouple HVM and IOMMU capabilities Wei Liu
2018-08-28 11:56   ` Jan Beulich

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=3c651e5f60a496e3e5661f60bd7e913dab2b05a0.1535285866.git-series.wei.liu2@citrix.com \
    --to=wei.liu2@citrix.com \
    --cc=andrew.cooper3@citrix.com \
    --cc=jbeulich@suse.com \
    --cc=xen-devel@lists.xenproject.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.