[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
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |