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

[Xen-devel] [PATCH v2 01/10] hvm/hpet: Add manual unit test code.



Add the code at tools/tests/vhpet.

Does repro the bug:

..MP-BIOS bug: 8254 timer not connected to IO-APIC

Signed-off-by: Don Slutz <dslutz@xxxxxxxxxxx>
---
 tools/tests/vhpet/.gitignore |   4 +
 tools/tests/vhpet/emul.h     | 405 ++++++++++++++++++++++++++++++++
 tools/tests/vhpet/main.c     | 541 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 950 insertions(+)
 create mode 100644 tools/tests/vhpet/.gitignore
 create mode 100644 tools/tests/vhpet/emul.h
 create mode 100644 tools/tests/vhpet/main.c

diff --git a/tools/tests/vhpet/.gitignore b/tools/tests/vhpet/.gitignore
new file mode 100644
index 0000000..6df805d
--- /dev/null
+++ b/tools/tests/vhpet/.gitignore
@@ -0,0 +1,4 @@
+test_vhpet
+hpet.h
+hpet.c
+foo
diff --git a/tools/tests/vhpet/emul.h b/tools/tests/vhpet/emul.h
new file mode 100644
index 0000000..a6f19e4
--- /dev/null
+++ b/tools/tests/vhpet/emul.h
@@ -0,0 +1,405 @@
+/*
+ * Xen emulation for hpet
+ *
+ * Copyright (C) 2014 Verizon Corporation
+ *
+ * This file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License Version 2 (GPLv2)
+ * as published by the Free Software Foundation.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details. <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <string.h>
+
+#define PCI_HAVE_64BIT_ADDRESS
+#include <pci/types.h>
+
+#include "hpet.h"
+
+#define NR_CPUS 8
+
+typedef int64_t s_time_t;
+typedef int spinlock_t;
+typedef int bool_t;
+
+#define BITS_PER_LONG __WORDSIZE
+#define BITS_TO_LONGS(bits) \
+    (((bits) + BITS_PER_LONG - 1) / BITS_PER_LONG)
+#define DECLARE_BITMAP(name, bits) \
+    unsigned long name[BITS_TO_LONGS(bits)]
+typedef struct cpumask
+{
+    DECLARE_BITMAP(bits, NR_CPUS);
+} cpumask_t;
+typedef cpumask_t *cpumask_var_t;
+struct msi_desc
+{
+    struct msi_attrib
+    {
+        u8    type    : 5;    /* {0: unused, 5h:MSI, 11h:MSI-X} */
+        u8    maskbit : 1;    /* mask-pending bit supported ?   */
+        u8    masked  : 1;
+        u8    is_64   : 1;    /* Address size: 0=32bit 1=64bit  */
+        u8    pos;            /* Location of the msi capability */
+        u16   entry_nr;       /* specific enabled entry         */
+    } msi_attrib;
+};
+
+struct msi_msg
+{
+    u32     address_lo;     /* low 32 bits of msi message address */
+    u32     address_hi;     /* high 32 bits of msi message address */
+    u32     data;           /* 16 bits of msi message data */
+    u32     dest32;         /* used when Interrupt Remapping with EIM is 
enabled */
+};
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+#endif
+
+#define X86EMUL_OKAY 100
+#define EINVAL 101
+
+#define DBG_LEVEL_PIT 200
+
+#define TRC_HW_VCHIP_HPET_START_TIMER 300
+#define TRC_HW_VCHIP_HPET_STOP_TIMER 301
+#define TRC_HW_VCHIP_PIT_STOP_TIMER 302
+
+#define TRC_HVM_VCHIP_HPET_START_TIMER 400
+#define TRC_HVM_VCHIP_HPET_STOP_TIMER 401
+#define TRC_HVM_VCHIP_PIT_STOP_TIMER 402
+
+#define TRC_HVM_EMUL_HPET_START_TIMER 400
+#define TRC_HVM_EMUL_HPET_STOP_TIMER 401
+#define TRC_HVM_EMUL_PIT_STOP_TIMER 402
+
+#define __read_mostly
+#define __initdata
+#define __init
+#define __maybe_unused
+#define __cacheline_aligned
+#define boolean_param(a, b)
+#define fix_to_virt(a) a
+#define xmalloc_array(_type, _num) (void *)(_type)(_num)
+#define DEFINE_PER_CPU(_type, _name) _type _name
+
+#define KERN_DEBUG
+#define KERN_INFO
+
+#define XENLOG_WARNING
+#define XENLOG_INFO
+#define XENLOG_ERR
+#define XENLOG_GUEST
+
+#define MSI_TYPE_UNKNOWN 0
+#define MSI_TYPE_HPET    1
+#define MSI_TYPE_IOMMU   2
+
+#define STIME_MAX ((s_time_t)((uint64_t)~0ull>>1))
+
+/* Low-latency softirqs come first in the following list. */
+enum
+{
+    TIMER_SOFTIRQ = 0,
+    SCHEDULE_SOFTIRQ,
+    NEW_TLBFLUSH_CLOCK_PERIOD_SOFTIRQ,
+    RCU_SOFTIRQ,
+    TASKLET_SOFTIRQ,
+    NR_COMMON_SOFTIRQS
+};
+/*
+ * ..and if you can't take the strict
+ * types, you can specify one yourself.
+ *
+ * Or not use min/max at all, of course.
+ */
+#define min_t(type, x, y) \
+    ({ type __x = (x); type __y = (y); __x < __y ? __x : __y; })
+#define max_t(type, x, y) \
+    ({ type __x = (x); type __y = (y); __x > __y ? __x : __y; })
+#define offsetof(t, m) ((unsigned long )&((t *)0)->m)
+#define container_of(ptr, type, member) ({              \
+        typeof( ((type *)0)->member ) *__mptr = (ptr);  \
+        (type *)( (char *)__mptr - offsetof(type,member) ); })
+
+struct domain;
+
+struct vcpu
+{
+    int vcpu_id;
+    struct domain *domain;
+};
+
+typedef void time_cb(struct vcpu *v, void *opaque);
+
+struct periodic_time
+{
+#define PTSRC_isa    1 /* ISA time source */
+#define PTSRC_lapic  2 /* LAPIC time source */
+    u8 source;                  /* PTSRC_ */
+};
+
+void destroy_periodic_time(struct periodic_time *pt);
+void create_periodic_time(
+    struct vcpu *v, struct periodic_time *pt, uint64_t delta,
+    uint64_t period, uint8_t irq, time_cb *cb, void *data);
+
+#define HPET_TIMER_NUM 3
+
+struct hpet_registers
+{
+    /* Memory-mapped, software visible registers */
+    uint64_t capability;        /* capabilities */
+    uint64_t config;            /* configuration */
+    uint64_t isr;               /* interrupt status reg */
+    uint64_t mc64;              /* main counter */
+    struct                      /* timers */
+    {
+        uint64_t config;        /* configuration/cap */
+        uint64_t cmp;           /* comparator */
+        uint64_t fsb;           /* FSB route, not supported now */
+    } timers[HPET_TIMER_NUM];
+
+    /* Hidden register state */
+    uint64_t period[HPET_TIMER_NUM]; /* Last value written to comparator */
+    uint64_t comparator64[HPET_TIMER_NUM]; /* 64 bit running comparator */
+    uint64_t first_mc64[HPET_TIMER_NUM]; /* 1st interval main counter */
+    uint8_t first_enabled[HPET_TIMER_NUM]; /* In 1st interval */
+};
+
+typedef struct HPETState
+{
+    struct hpet_registers hpet;
+    uint64_t stime_freq;
+    uint64_t hpet_to_ns_scale; /* hpet ticks to ns (multiplied by 2^10) */
+    uint64_t hpet_to_ns_limit; /* max hpet ticks convertable to ns      */
+    uint64_t mc_offset;
+    struct periodic_time pt[HPET_TIMER_NUM];
+    spinlock_t lock;
+} HPETState;
+
+typedef struct PITState
+{
+    struct periodic_time pt0;
+    spinlock_t lock;
+} PITState;
+
+
+struct pl_time      /* platform time */
+{
+    struct HPETState vhpet;
+    /* guest_time = Xen sys time + stime_offset */
+    int64_t stime_offset;
+    /* Ensures monotonicity in appropriate timer modes. */
+    uint64_t last_guest_time;
+    spinlock_t pl_time_lock;
+};
+
+#define HVM_PARAM_HPET_ENABLED 11
+
+struct hvm_domain
+{
+    struct pl_time         pl_time;
+    long params[20];
+};
+
+struct arch_domain
+{
+    struct hvm_domain hvm_domain;
+    struct PITState vpit;
+};
+
+struct domain
+{
+    int domain_id;
+    struct arch_domain arch;
+    struct vcpu *vcpu[NR_CPUS];
+};
+
+typedef int (*hvm_mmio_read_t)(struct vcpu *v,
+                               unsigned long addr,
+                               unsigned long length,
+                               unsigned long *val);
+typedef int (*hvm_mmio_write_t)(struct vcpu *v,
+                                unsigned long addr,
+                                unsigned long length,
+                                unsigned long val);
+typedef int (*hvm_mmio_check_t)(struct vcpu *v, unsigned long addr);
+
+
+struct hvm_mmio_handler
+{
+    hvm_mmio_check_t check_handler;
+    hvm_mmio_read_t read_handler;
+    hvm_mmio_write_t write_handler;
+};
+
+/* Marshalling and unmarshalling uses a buffer with size and cursor. */
+typedef struct hvm_domain_context
+{
+    uint32_t cur;
+    uint32_t size;
+    uint8_t *data;
+} hvm_domain_context_t;
+
+int current_domain_id(void);
+#define dprintk(_l, _f, _a...)                  \
+    printk(_l "%s:%d: " _f, __FILE__ , __LINE__ , ## _a )
+#define gdprintk(_l, _f, _a...)                         \
+    printk(XENLOG_GUEST _l "%s:%d:d%d " _f, __FILE__,   \
+           __LINE__, current_domain_id() , ## _a )
+struct vcpu *get_current();
+#define current get_current()
+
+#define HVM_SAVE_CODE(_x) HVM_SAVE_CODE_##_x
+#define HVM_SAVE_LENGTH(_x) HVM_SAVE_LENGTH_##_x
+
+/*
+ * HPET
+ */
+
+uint64_t hvm_get_guest_time(struct vcpu *v);
+
+#define HPET_TIMER_NUM     3    /* 3 timers supported now */
+struct hvm_hw_hpet
+{
+    /* Memory-mapped, software visible registers */
+    uint64_t capability;        /* capabilities */
+    uint64_t res0;              /* reserved */
+    uint64_t config;            /* configuration */
+    uint64_t res1;              /* reserved */
+    uint64_t isr;               /* interrupt status reg */
+    uint64_t res2[25];          /* reserved */
+    uint64_t mc64;              /* main counter */
+    uint64_t res3;              /* reserved */
+    struct                      /* timers */
+    {
+        uint64_t config;        /* configuration/cap */
+        uint64_t cmp;           /* comparator */
+        uint64_t fsb;           /* FSB route, not supported now */
+        uint64_t res4;          /* reserved */
+    } timers[HPET_TIMER_NUM];
+    uint64_t res5[4 * (24 - HPET_TIMER_NUM)]; /* reserved, up to 0x3ff */
+
+    /* Hidden register state */
+    uint64_t period[HPET_TIMER_NUM]; /* Last value written to comparator */
+};
+
+typedef int (*hvm_save_handler)(struct domain *d,
+                                hvm_domain_context_t *h);
+typedef int (*hvm_load_handler)(struct domain *d,
+                                hvm_domain_context_t *h);
+
+struct hvm_save_descriptor
+{
+    uint16_t typecode;          /* Used to demux the various types below */
+    uint16_t instance;          /* Further demux within a type */
+    uint32_t length;            /* In bytes, *not* including this descriptor */
+};
+
+void hvm_register_savevm(uint16_t typecode,
+                         const char *name,
+                         hvm_save_handler save_state,
+                         hvm_load_handler load_state,
+                         size_t size, int kind);
+
+#define HVMSR_PER_DOM 1
+
+#define HVM_REGISTER_SAVE_RESTORE(_x, _save, _load, _num, _k)       \
+    int __init __hvm_register_##_x##_save_and_restore(void)     \
+    {                                                                   \
+        hvm_register_savevm(HVM_SAVE_CODE(_x),                          \
+                            #_x,                                        \
+                            &_save,                                     \
+                            &_load,                                     \
+                            (_num) * (HVM_SAVE_LENGTH(_x)               \
+                                 + sizeof(struct hvm_save_descriptor)), \
+                            _k);                                        \
+        return 0;                                                       \
+    }                                                                   \
+
+#define HVM_SAVE_CODE_HPET 0
+#define HVM_SAVE_LENGTH_HPET sizeof(struct hvm_hw_hpet)
+
+#define printk printf
+
+#define spin_lock(a)
+#define spin_unlock(a)
+#define spin_lock_init(a)
+#define spin_is_locked(a) 1
+#define ASSERT(a)
+
+#define ADDR (*(volatile long *) addr)
+
+static inline void __set_bit(int nr, volatile void *addr)
+{
+    asm volatile(
+        "btsl %1,%0"
+        : "=m"(ADDR)
+        : "Ir"(nr), "m"(ADDR) : "memory");
+}
+
+static inline void __clear_bit(int nr, volatile void *addr)
+{
+    asm volatile(
+        "btrl %1,%0"
+        : "=m"(ADDR)
+        : "Ir"(nr), "m"(ADDR) : "memory");
+}
+
+static inline unsigned int find_first_set_bit(unsigned long word)
+{
+    asm("bsf %1,%0" : "=r"(word) : "r"(word));
+    return (unsigned int)word;
+}
+
+#define HVM_DBG_LOG(level, _f, _a...)                   \
+    do {                                \
+        printf("[HVM:%d.%d] <%s> " _f "\n",                             \
+               current->domain->domain_id, current->vcpu_id, __func__,  \
+               ## _a);                                                  \
+    } while ( 0 )
+
+void __domain_crash(struct domain *d);
+#define domain_crash(d) do {                        \
+        printf("domain_crash called from %s:%d\n", __FILE__, __LINE__); \
+        __domain_crash(d);                                              \
+    } while ( 0 )
+
+#define MICROSECS(_us) ((s_time_t)((_us) * 1000ULL))
+
+#define pt_global_vcpu_target(d)        \
+    ((d)->vcpu ? (d)->vcpu[0] : NULL)
+
+#define TRACE_0D(a)
+#define TRACE_1D(a, b)
+#define TRACE_2D(a, b, c)
+#define TRACE_3D(a, b, c, d)
+#define TRACE_4D(a, b, c, d, e)
+#define TRACE_5D(a, b, c, d, e, f)
+
+/* debug */
+
+extern int __read_mostly hpet_debug;
+extern uint64_t __read_mostly hpet_force_diff;
+extern uint64_t __read_mostly hpet_force_mc64;
+extern uint64_t __read_mostly hpet_force_cmp;
+extern uint64_t __read_mostly hpet_force_period;
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tools/tests/vhpet/main.c b/tools/tests/vhpet/main.c
new file mode 100644
index 0000000..c74ed85
--- /dev/null
+++ b/tools/tests/vhpet/main.c
@@ -0,0 +1,541 @@
+/*
+ * Xen emulation for hpet
+ *
+ * Copyright (C) 2014 Verizon Corporation
+ *
+ * This file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License Version 2 (GPLv2)
+ * as published by the Free Software Foundation.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details. <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * 
http://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/software-developers-hpet-spec-1-0a.pdf
+ *
+ * xen_source is a directory that has all xen source below it.
+ *
+ * Usage:
+ *
+
+
+  xen_source=../../..
+  sed -e "/#include/d" -e "1i#include \"emul.h\"\n" 
<$xen_source/xen/arch/x86/hvm/hpet.c >hpet.c
+  cp $xen_source/xen/include/asm-x86/hpet.h .
+
+  gcc -g -o test_vhpet hpet.c main.c
+  ./test_vhpet >foo
+
+ *
+ *
+ * Also bad values for 3243567890123456 just not negative.
+ *
+ */
+
+#define FORCE_THOUSANDS_SEP
+
+#include <locale.h>
+#include <langinfo.h>
+#include <stdarg.h>
+#include "emul.h"
+#include "hpet.h"
+
+#define S_TO_NS    1000000000ULL           /* 1s  = 10^9  ns */
+
+#define START_MC64 0x108a8
+
+static int hpet_mult = 1;
+static int hpet_add;
+static int hvm_clock_cost = 1234567;
+static int tick_count = 1;
+static int debug = 3;
+
+static int skip_load;
+
+static char *global_thousep;
+
+extern const struct hvm_mmio_handler hpet_mmio_handler;
+
+struct domain dom1;
+struct vcpu vcpu0;
+struct hvm_hw_hpet hpet_save;
+
+
+uint64_t hvm_guest_time;
+
+static struct
+{
+    hvm_save_handler save;
+    hvm_load_handler load;
+    const char *name;
+    size_t size;
+    int kind;
+} hvm_sr_handlers[3] = {{NULL, NULL, "<?>"},};
+
+static uint64_t new_guest_time[] = {
+    0x20,
+    0x2a840,
+    0xf4200,
+    0x10000000000ULL,
+    0x0fffffffffefff00ULL,
+    0x20,
+    0xffffffff00000000ULL,
+    0x20,
+};
+
+static int print_error(const char *fmt, ...)
+{
+    va_list args;
+    int i = 0;
+
+    va_start(args, fmt);
+    if ( debug & 0x0001 )
+        i = vfprintf(stdout, fmt, args);
+    va_end(args);
+    va_start(args, fmt);
+    if ( debug & 0x0002 )
+        i = vfprintf(stderr, fmt, args);
+    va_end(args);
+    return i;
+}
+
+
+int current_domain_id(void)
+{
+    return current->domain->domain_id;
+}
+
+struct vcpu *get_current()
+{
+    return &vcpu0;
+}
+
+void __domain_crash(struct domain *d)
+{
+    exit(42);
+}
+
+uint64_t hvm_get_guest_time(struct vcpu *v)
+{
+    uint64_t ret = hvm_guest_time;
+
+    hvm_guest_time += hvm_clock_cost;
+    return ret;
+}
+
+int _hvm_init_entry(struct hvm_domain_context *h,
+                    uint16_t tc, uint16_t inst, uint32_t len)
+{
+    h->cur = 0;
+    h->size = sizeof(hpet_save);
+    h->data = (void *)&hpet_save;
+
+    return 0;
+}
+
+int _hvm_check_entry(struct hvm_domain_context *h,
+                     uint16_t type, uint32_t len, bool_t strict_length)
+{
+    h->cur = 0;
+    h->size = sizeof(hpet_save);
+    h->data = (void *)&hpet_save;
+
+    return 0;
+}
+
+void __init hvm_register_savevm(uint16_t typecode,
+                                const char *name,
+                                hvm_save_handler save_state,
+                                hvm_load_handler load_state,
+                                size_t size, int kind)
+{
+    hvm_sr_handlers[typecode].save = save_state;
+    hvm_sr_handlers[typecode].load = load_state;
+    hvm_sr_handlers[typecode].name = name;
+    hvm_sr_handlers[typecode].size = size;
+    hvm_sr_handlers[typecode].kind = kind;
+}
+
+int do_save(uint16_t typecode, struct domain *d, hvm_domain_context_t *h)
+{
+    return hvm_sr_handlers[typecode].save(d, h);
+}
+
+int do_load(uint16_t typecode, struct domain *d, hvm_domain_context_t *h)
+{
+    if (skip_load > 0)
+    {
+        printf("skip_load\n");
+    }
+    else
+    {
+        printf("do_load\n");
+        return hvm_sr_handlers[typecode].load(d, h);
+    }
+}
+
+static void dump_hpet(void)
+{
+    int i;
+    unsigned long long conf;
+    struct hvm_hw_hpet h = hpet_save;
+    conf = (unsigned long long) h.config;
+    printf("    HPET: capability %#llx config %#llx(%s%s)\n",
+           (unsigned long long) h.capability,
+           conf,
+           conf & HPET_CFG_ENABLE ? "E" : "",
+           conf & HPET_CFG_LEGACY ? "L" : "");
+    printf("          isr %#llx counter %#llx(%'lld)\n",
+           (unsigned long long) h.isr,
+           (unsigned long long) h.mc64,
+           (unsigned long long) h.mc64);
+    for (i = 0; i < HPET_TIMER_NUM; i++)
+    {
+        conf = (unsigned long long) h.timers[i].config;
+        printf("          timer%i config %#llx(%s%s%s) cmp %#llx(%'lld)\n", i,
+               conf,
+               conf & HPET_TN_ENABLE ? "E" : "",
+               conf & HPET_TN_PERIODIC ? "P" : "",
+               conf & HPET_TN_32BIT ? "32" : "",
+               (unsigned long long) h.timers[i].cmp,
+               (unsigned long long) h.timers[i].cmp);
+        printf("          timer%i period %#llx(%'lld) fsb %#llx\n", i,
+               (unsigned long long) h.period[i],
+               (unsigned long long) h.period[i],
+               (unsigned long long) h.timers[i].fsb);
+    }
+}
+
+void pit_stop_channel0_irq(PITState *pit)
+{
+    printf("pit_stop_channel0_irq: pit=%p\n", pit);
+
+    TRACE_1D(TRC_HVM_VCHIP_PIT_STOP_TIMER, get_cycles());
+    spin_lock(&pit->lock);
+    destroy_periodic_time(&pit->pt0);
+    spin_unlock(&pit->lock);
+}
+
+void destroy_periodic_time(struct periodic_time *pt)
+{
+    int idx = ((long)pt) & 0x7;
+
+    printf("destroy_periodic_time: pt=%d\n", idx);
+}
+
+void create_periodic_time(
+    struct vcpu *v, struct periodic_time *pt, uint64_t delta,
+    uint64_t period, uint8_t irq, time_cb *cb, void *data)
+{
+    int idx = ((long)pt) & 0x7;
+
+    if ( period )
+    {
+        printf("create_periodic_time: pt=%d delta=%'"PRId64" period=%'"PRIu64
+               " - %'"PRIu64".%02d Hz irq=%d\n",
+               idx, delta, period, (uint64_t)(S_TO_NS / period),
+               (int)((S_TO_NS / (period / 100ULL)) % 100), irq);
+        /* +160 is for hpet_tick_to_ns() not simple. */
+        if ( delta > (period * (hpet_mult + hpet_add + 160)) )
+            print_error("Possible ..MP-BIOS bug: 8254 timer...: delta=%'"PRId64
+                        " period=%'"PRIu64"\n",
+                        delta, period);
+    }
+    else
+        printf("create_periodic_time: pt=%d delta=%'"PRId64
+               " period=%'"PRIu64" irq=%d\n",
+               idx, delta, period, irq);
+}
+
+void udelay(int w)
+{
+}
+
+unsigned int hpet_readl(unsigned long a)
+{
+    unsigned long ret = 0;
+    hpet_mmio_handler.read_handler(current, a, 4, &ret);
+    return ret;
+}
+
+void hpet_writel(unsigned long d, unsigned long a)
+{
+    hpet_mmio_handler.write_handler(current, a, 4, d);
+    return;
+}
+
+static void _hpet_print_config(const char *function, int line)
+{
+    u32 i, timers, l, h;
+    printk(KERN_INFO "hpet: %s(%d):\n", function, line);
+    l = hpet_readl(HPET_ID);
+    h = hpet_readl(HPET_PERIOD);
+    timers = ((l & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT) + 1;
+    printk(KERN_INFO "hpet: ID: 0x%x, PERIOD: 0x%x\n", l, h);
+    l = hpet_readl(HPET_CFG);
+    h = hpet_readl(HPET_STATUS);
+    printk(KERN_INFO "hpet: CFG: 0x%x, STATUS: 0x%x\n", l, h);
+    l = hpet_readl(HPET_COUNTER);
+    h = hpet_readl(HPET_COUNTER + 4);
+    printk(KERN_INFO "hpet: COUNTER_l: 0x%x, COUNTER_h: 0x%x\n", l, h);
+
+    for (i = 0; i < timers; i++)
+    {
+        l = hpet_readl(HPET_Tn_CFG(i));
+        h = hpet_readl(HPET_Tn_CFG(i) + 4);
+        printk(KERN_INFO "hpet: T%d: CFG_l: 0x%x, CFG_h: 0x%x\n",
+               i, l, h);
+        l = hpet_readl(HPET_Tn_CMP(i));
+        h = hpet_readl(HPET_Tn_CMP(i) + 4);
+        printk(KERN_INFO "hpet: T%d: CMP_l: 0x%x, CMP_h: 0x%x\n",
+               i, l, h);
+        l = hpet_readl(HPET_Tn_ROUTE(i));
+        h = hpet_readl(HPET_Tn_ROUTE(i) + 4);
+        printk(KERN_INFO "hpet: T%d ROUTE_l: 0x%x, ROUTE_h: 0x%x\n",
+               i, l, h);
+    }
+}
+
+#define hpet_print_config()                                     \
+    do {                                                            \
+        _hpet_print_config(__func__, __LINE__);     \
+    } while ( 0 )
+
+static void hpet_stop_counter(void)
+{
+    unsigned long cfg = hpet_readl(HPET_CFG);
+    cfg &= ~HPET_CFG_ENABLE;
+    hpet_writel(cfg, HPET_CFG);
+}
+
+static void hpet_reset_counter(void)
+{
+    hpet_writel(0, HPET_COUNTER);
+    hpet_writel(0, HPET_COUNTER + 4);
+}
+
+static void hpet_start_counter(void)
+{
+    unsigned long cfg = hpet_readl(HPET_CFG);
+    cfg |= HPET_CFG_ENABLE;
+    hpet_writel(cfg, HPET_CFG);
+}
+
+static void hpet_restart_counter(void)
+{
+    hpet_stop_counter();
+    hpet_reset_counter();
+    hpet_start_counter();
+}
+
+static void hpet_set_mode(uint64_t delta, int timer)
+{
+    unsigned long cfg, cmp, cmp2, now;
+
+    hpet_stop_counter();
+    now = hpet_readl(HPET_COUNTER);
+    cmp = now + (unsigned long)(hpet_mult * delta) + hpet_add;
+    cfg = hpet_readl(HPET_Tn_CFG(timer));
+    /* Make sure we use edge triggered interrupts */
+    cfg &= ~HPET_TN_LEVEL;
+    cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC |
+           HPET_TN_SETVAL | HPET_TN_32BIT;
+    /* Mask to 32 bits just like the hardware */
+    cmp = (uint32_t)cmp;
+    delta = (uint32_t)delta;
+    /* Do the config */
+    hpet_writel(cfg, HPET_Tn_CFG(timer));
+    hpet_writel(cmp, HPET_Tn_CMP(timer));
+    printf("hpet_writel: HPET_TN_SETVAL cmp=%#lx(%'ld) timer=%d\n",
+           cmp, cmp, timer);
+    udelay(1);
+    /*
+     * HPET on AMD 81xx needs a second write (with HPET_TN_SETVAL
+     * cleared) to T0_CMP to set the period. The HPET_TN_SETVAL
+     * bit is automatically cleared after the first write.
+     * (See AMD-8111 HyperTransport I/O Hub Data Sheet,
+     * Publication # 24674)
+     */
+    hpet_writel((unsigned long) delta, HPET_Tn_CMP(timer));
+    printf("hpet_writel: period=%#lx(%'ld) timer=%d\n",
+           (unsigned long) delta, (unsigned long) delta, timer);
+    cmp2 = hpet_readl(HPET_Tn_CMP(timer));
+    if ( cmp2 != cmp )
+        print_error("hpet: T%d Error: Set %#lx(%'ld) != %#lx(%'ld)\n",
+                    timer, cmp, cmp, cmp2, cmp2);
+    hpet_start_counter();
+    hpet_print_config();
+}
+
+int
+main(int argc, char **argv)
+{
+    hvm_domain_context_t hdc;
+    struct hvm_hw_hpet hpet0;
+    struct hvm_hw_hpet hpet1;
+    struct hvm_hw_hpet hpet2;
+    int i, k;
+
+    setlocale(LC_ALL, "");
+
+#ifdef FORCE_THOUSANDS_SEP
+    setlocale(LC_NUMERIC, "en_US.utf8");
+#endif
+    global_thousep = nl_langinfo(THOUSEP);
+
+    printf("test_vhpet 1.0\n");
+
+    if ( argc > 1 )
+        hvm_clock_cost = atoi(argv[1]);
+    if ( argc > 2 )
+        hpet_mult = atoi(argv[2]);
+    if ( argc > 3 )
+        hpet_add = atoi(argv[3]);
+    if ( argc > 4 )
+        tick_count = atoi(argv[4]);
+    if ( argc > 5 )
+        debug = strtol(argv[5], NULL, 0);
+
+    printf("hvm_clock_cost=%'d hpet_mult=%'d hpet_add=%'d tick_count=%d 
debug=%#x\n",
+           hvm_clock_cost, hpet_mult, hpet_add, tick_count, debug);
+
+    dom1.domain_id = 1;
+    dom1.vcpu[0] = &vcpu0;
+    vcpu0.vcpu_id = 0;
+    vcpu0.domain = &dom1;
+
+    __hvm_register_HPET_save_and_restore();
+
+    for (skip_load = 1; skip_load >= 0; skip_load--)
+    {
+
+        printf("\nskip_load=%d\n", skip_load);
+
+        hvm_guest_time = 16;
+
+        hpet_init(&vcpu0);
+
+        do_save(HVM_SAVE_CODE(HPET), &dom1, &hdc);
+        dump_hpet();
+        hpet0 = hpet_save;
+        do_save(HVM_SAVE_CODE(HPET), &dom1, &hdc);
+        dump_hpet();
+        hpet1 = hpet_save;
+        if (hpet0.mc64 != hpet1.mc64)
+            print_error("With clock stopped mc64 changed: %'ld to %'ld\n",
+                        hpet0.mc64, hpet1.mc64);
+
+        do_load(HVM_SAVE_CODE(HPET), &dom1, &hdc);
+        do_save(HVM_SAVE_CODE(HPET), &dom1, &hdc);
+        dump_hpet();
+        hpet2 = hpet_save;
+        if (hpet1.mc64 != hpet2.mc64)
+            print_error("With clock stopped mc64 changed: %'ld to %'ld\n",
+                        hpet1.mc64, hpet2.mc64);
+
+        dom1.arch.hvm_domain.pl_time.vhpet.hpet.mc64 = START_MC64;
+        dom1.arch.hvm_domain.pl_time.vhpet.mc_offset = START_MC64
+            - hvm_guest_time - hvm_clock_cost;
+        printf("\n"
+               "mc64=%#lx(%'ld) mc_offset=%#lx(%'ld)\n",
+               dom1.arch.hvm_domain.pl_time.vhpet.hpet.mc64,
+               dom1.arch.hvm_domain.pl_time.vhpet.hpet.mc64,
+               dom1.arch.hvm_domain.pl_time.vhpet.mc_offset,
+               dom1.arch.hvm_domain.pl_time.vhpet.mc_offset);
+
+        printf("\nhvm_guest_time=%#lx(%'ld)\n",
+               hvm_guest_time, hvm_guest_time);
+
+        do_save(HVM_SAVE_CODE(HPET), &dom1, &hdc);
+        dump_hpet();
+        hpet0 = hpet_save;
+        do_save(HVM_SAVE_CODE(HPET), &dom1, &hdc);
+        dump_hpet();
+        hpet1 = hpet_save;
+        if (hpet0.mc64 != hpet1.mc64)
+            print_error("With clock stopped mc64 changed: %'ld to %'ld\n",
+                        hpet0.mc64, hpet1.mc64);
+
+        do_load(HVM_SAVE_CODE(HPET), &dom1, &hdc);
+        do_save(HVM_SAVE_CODE(HPET), &dom1, &hdc);
+        dump_hpet();
+        hpet2 = hpet_save;
+        if (hpet1.mc64 != hpet2.mc64)
+            print_error("With clock stopped mc64 changed: %'ld to %'ld\n",
+                        hpet1.mc64, hpet2.mc64);
+
+        hpet_set_mode(0xf424, 0);
+        hpet_set_mode(0, 1);
+#ifdef BIG
+        hpet_set_mode(~0ULL, 2);
+#else
+        hpet_set_mode(0x80000000, 2);
+#endif
+
+        do_save(HVM_SAVE_CODE(HPET), &dom1, &hdc);
+        dump_hpet();
+        hpet0 = hpet_save;
+        do_save(HVM_SAVE_CODE(HPET), &dom1, &hdc);
+        dump_hpet();
+        hpet1 = hpet_save;
+
+        do_load(HVM_SAVE_CODE(HPET), &dom1, &hdc);
+        do_save(HVM_SAVE_CODE(HPET), &dom1, &hdc);
+        dump_hpet();
+        hpet2 = hpet_save;
+
+
+        for (k = 0; k < ARRAY_SIZE(new_guest_time); k++)
+        {
+            hvm_guest_time = new_guest_time[k];
+            printf("\nhvm_guest_time=%#lx(%'ld)\n",
+                   hvm_guest_time, hvm_guest_time);
+
+            do_save(HVM_SAVE_CODE(HPET), &dom1, &hdc);
+            dump_hpet();
+            hpet0 = hpet_save;
+            do_save(HVM_SAVE_CODE(HPET), &dom1, &hdc);
+            dump_hpet();
+            hpet1 = hpet_save;
+
+            do_load(HVM_SAVE_CODE(HPET), &dom1, &hdc);
+            do_save(HVM_SAVE_CODE(HPET), &dom1, &hdc);
+            dump_hpet();
+            hpet2 = hpet_save;
+
+            for (i = 0; i < tick_count; i++)
+            {
+                hvm_guest_time += 0x10;
+                printf("\nhvm_guest_time=%#lx(%'ld)\n",
+                       hvm_guest_time, hvm_guest_time);
+
+                do_save(HVM_SAVE_CODE(HPET), &dom1, &hdc);
+                dump_hpet();
+                hpet0 = hpet_save;
+                do_save(HVM_SAVE_CODE(HPET), &dom1, &hdc);
+                dump_hpet();
+                hpet1 = hpet_save;
+
+                do_load(HVM_SAVE_CODE(HPET), &dom1, &hdc);
+                do_save(HVM_SAVE_CODE(HPET), &dom1, &hdc);
+                dump_hpet();
+                hpet2 = hpet_save;
+
+            }
+        }
+    }
+
+    return 0;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
-- 
1.8.4


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

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