mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 18:21:39 +01:00
The struct just contains three methods and no data, so the name hvm_mmio_ops more accurately reflects its content. A subsequent patch introduces a new structure which more accurately warrants the name hvm_mmio_handler so doing the rename in this purely cosmetic patch avoids conflating functional and cosmetic changes in a single patch. Signed-off-by: Paul Durrant <paul.durrant@citrix.com> Acked-by: Jan Beulich <jbeulich@suse.com>
777 lines
24 KiB
C
777 lines
24 KiB
C
/*
|
|
* 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 >test_vhpet.out
|
|
|
|
*
|
|
*
|
|
* This is almost the same as
|
|
*
|
|
|
|
make run
|
|
|
|
*
|
|
* Or
|
|
*
|
|
* make -C tools/tests/vhpet run
|
|
*
|
|
* From a xen source tree. The differance
|
|
* is that you need to be in a xen source tree
|
|
* and normal make rules apply.
|
|
*
|
|
*/
|
|
|
|
#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 int skip_error_on_load;
|
|
|
|
static char *global_thousep;
|
|
|
|
extern const struct hvm_mmio_ops hpet_mmio_ops;
|
|
|
|
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;
|
|
|
|
if ( (debug & 0x0100) && skip_error_on_load )
|
|
return i;
|
|
|
|
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 & 0x1)
|
|
{
|
|
printf("skip_load=%#x\n", skip_load);
|
|
}
|
|
else
|
|
{
|
|
int ret;
|
|
|
|
printf("do_load\n");
|
|
skip_error_on_load = 1;
|
|
ret = hvm_sr_handlers[typecode].load(d, h);
|
|
skip_error_on_load = 0;
|
|
}
|
|
}
|
|
|
|
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 ( debug & 0x0010 )
|
|
{
|
|
int i;
|
|
|
|
printf("create_periodic_time: "
|
|
"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);
|
|
for (i = 0; i < 3; i++)
|
|
{
|
|
printf(" "
|
|
"[%d] cmp64=%#lx(%'ld) cmp=%#lx(%'ld)\n", i,
|
|
dom1.arch.hvm_domain.pl_time.vhpet.hpet.comparator64[i],
|
|
dom1.arch.hvm_domain.pl_time.vhpet.hpet.comparator64[i],
|
|
dom1.arch.hvm_domain.pl_time.vhpet.hpet.timers[i].cmp,
|
|
dom1.arch.hvm_domain.pl_time.vhpet.hpet.timers[i].cmp);
|
|
}
|
|
}
|
|
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("%s(%ld): Possible ..MP-BIOS bug: 8254 timer...: delta=%'"PRId64
|
|
" period=%'"PRIu64"\n", __func__, __LINE__,
|
|
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_ops.read(current, a, 4, &ret);
|
|
return ret;
|
|
}
|
|
|
|
void hpet_writel(unsigned long d, unsigned long a)
|
|
{
|
|
hpet_mmio_ops.write(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(unsigned long low, unsigned long high)
|
|
{
|
|
hpet_writel(low, HPET_COUNTER);
|
|
hpet_writel(high, 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(0, 0);
|
|
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("%s(%ld): HPET_TN_SETVAL cmp=%#lx(%'ld) timer=%d\n",
|
|
__func__, __LINE__, 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("%s(%ld): period=%#lx(%'ld) timer=%d\n", __func__, __LINE__,
|
|
(unsigned long) delta, (unsigned long) delta, timer);
|
|
cmp2 = hpet_readl(HPET_Tn_CMP(timer));
|
|
if ( cmp2 != cmp )
|
|
print_error("%s(%ld): T%d Error: Set %#lx(%'ld) != %#lx(%'ld)\n",
|
|
__func__, __LINE__, timer, cmp, cmp, cmp2, cmp2);
|
|
|
|
hpet_start_counter();
|
|
hpet_print_config();
|
|
}
|
|
|
|
|
|
hpet_check_stopped(uint64_t old_delta, int timer)
|
|
{
|
|
unsigned long mc_low, mc_high, old_cmp, now;
|
|
unsigned long cfg, cmp, delta, cmp2, cmp3;
|
|
|
|
if (skip_load & 0x2)
|
|
{
|
|
printf("Skip hpet_check_stopped. skip_load=%#x\n", skip_load);
|
|
return;
|
|
}
|
|
hpet_stop_counter();
|
|
mc_low = hpet_readl(HPET_COUNTER);
|
|
mc_high = hpet_readl(HPET_COUNTER + 4);
|
|
old_cmp = hpet_readl(HPET_Tn_CMP(timer));
|
|
|
|
hpet_reset_counter(67752, 0);
|
|
cmp = 255252;
|
|
delta = 62500;
|
|
|
|
now = hpet_readl(HPET_COUNTER);
|
|
if ( now != 67752 )
|
|
print_error("%s(%ld): T%d Error: Set mc %#lx(%'ld) != %#lx(%'ld)\n",
|
|
__func__, __LINE__, timer, 67752, 67752, now, now);
|
|
cfg = hpet_readl(HPET_Tn_CFG(timer));
|
|
cfg |= HPET_TN_SETVAL;
|
|
hpet_writel(cfg, HPET_Tn_CFG(timer));
|
|
hpet_writel(cmp, HPET_Tn_CMP(timer));
|
|
printf("%s(%ld): HPET_TN_SETVAL cmp=%#lx(%'ld) timer=%d\n",
|
|
__func__, __LINE__, cmp, cmp, timer);
|
|
cmp2 = hpet_readl(HPET_Tn_CMP(timer));
|
|
if ( cmp2 != cmp )
|
|
print_error("%s(%ld): T%d Error: Set cmp %#lx(%'ld) != %#lx(%'ld)\n",
|
|
__func__, __LINE__, timer, cmp, cmp, cmp2, cmp2);
|
|
|
|
hpet_writel((unsigned long) delta, HPET_Tn_CMP(timer));
|
|
printf("%s(%ld): period=%#lx(%'ld) timer=%d\n", __func__, __LINE__,
|
|
(unsigned long) delta, (unsigned long) delta, timer);
|
|
cmp3 = hpet_readl(HPET_Tn_CMP(timer));
|
|
if ( cmp3 != cmp )
|
|
print_error("%s(%ld): T%d Error: Set period, cmp %#lx(%'ld) != %#lx(%'ld)\n",
|
|
__func__, __LINE__, timer, cmp, cmp, cmp3, cmp3);
|
|
|
|
if ( dom1.arch.hvm_domain.pl_time.vhpet.hpet.period[timer] != delta )
|
|
printf("%s(%ld): T%d Warning: Set period %#lx(%'ld) != %#lx(%'ld)\n",
|
|
__func__, __LINE__, timer, delta, delta,
|
|
dom1.arch.hvm_domain.pl_time.vhpet.hpet.period[timer],
|
|
dom1.arch.hvm_domain.pl_time.vhpet.hpet.period[timer]);
|
|
|
|
hpet_reset_counter(67752, 0);
|
|
cmp = 255252;
|
|
delta = 62500;
|
|
|
|
now = hpet_readl(HPET_COUNTER);
|
|
if ( now != 67752 )
|
|
print_error("%s(%ld): T%d Error: Set mc %#lx(%'ld) != %#lx(%'ld)\n",
|
|
__func__, __LINE__, timer, 67752, 67752, now, now);
|
|
cfg = hpet_readl(HPET_Tn_CFG(timer));
|
|
cfg |= HPET_TN_SETVAL;
|
|
hpet_writel(cfg, HPET_Tn_CFG(timer));
|
|
hpet_writel(cmp, HPET_Tn_CMP(timer));
|
|
printf("%s(%ld): HPET_TN_SETVAL cmp=%#lx(%'ld) timer=%d\n",
|
|
__func__, __LINE__, cmp, cmp, timer);
|
|
cmp2 = hpet_readl(HPET_Tn_CMP(timer));
|
|
if ( cmp2 != cmp )
|
|
print_error("%s(%ld): T%d Error: Set cmp %#lx(%'ld) != %#lx(%'ld)\n",
|
|
__func__, __LINE__, timer, cmp, cmp, cmp2, cmp2);
|
|
|
|
hpet_writel((unsigned long) delta, HPET_Tn_CMP(timer));
|
|
printf("%s(%ld): period=%#lx(%'ld) timer=%d\n", __func__, __LINE__,
|
|
(unsigned long) delta, (unsigned long) delta, timer);
|
|
cmp3 = hpet_readl(HPET_Tn_CMP(timer));
|
|
if ( cmp3 != cmp )
|
|
print_error("%s(%ld): T%d Error: Set period, cmp %#lx(%'ld) != %#lx(%'ld)\n",
|
|
__func__, __LINE__, timer, cmp, cmp, cmp3, cmp3);
|
|
|
|
if ( dom1.arch.hvm_domain.pl_time.vhpet.hpet.period[timer] != delta )
|
|
printf("%s(%ld): T%d Warning: Set period %#lx(%'ld) != %#lx(%'ld)\n",
|
|
__func__, __LINE__, timer, delta, delta,
|
|
dom1.arch.hvm_domain.pl_time.vhpet.hpet.period[timer],
|
|
dom1.arch.hvm_domain.pl_time.vhpet.hpet.period[timer]);
|
|
|
|
hpet_reset_counter(67700, 0);
|
|
|
|
now = hpet_readl(HPET_COUNTER);
|
|
if ( now != 67700 )
|
|
print_error("%s(%ld): T%d Error: Set mc %#lx(%'ld) != %#lx(%'ld)\n",
|
|
__func__, __LINE__, timer, 67752, 67752, now, now);
|
|
cmp2 = hpet_readl(HPET_Tn_CMP(timer));
|
|
if ( cmp2 != cmp )
|
|
print_error("%s(%ld): T%d Error: Set mc, cmp %#lx(%'ld) != %#lx(%'ld)\n",
|
|
__func__, __LINE__, timer, cmp, cmp, cmp2, cmp2);
|
|
|
|
cmp3 = hpet_readl(HPET_Tn_CMP(timer));
|
|
if ( cmp3 != cmp )
|
|
print_error("%s(%ld): T%d Error: Set mc, cmp %#lx(%'ld) != %#lx(%'ld)\n",
|
|
__func__, __LINE__, timer, cmp, cmp, cmp3, cmp3);
|
|
|
|
if ( dom1.arch.hvm_domain.pl_time.vhpet.hpet.period[timer] != delta )
|
|
printf("%s(%ld): T%d Warning: Set mc, period %#lx(%'ld) != %#lx(%'ld)\n",
|
|
__func__, __LINE__, timer, delta, delta,
|
|
dom1.arch.hvm_domain.pl_time.vhpet.hpet.period[timer],
|
|
dom1.arch.hvm_domain.pl_time.vhpet.hpet.period[timer]);
|
|
|
|
cmp = 67701;
|
|
|
|
now = hpet_readl(HPET_COUNTER);
|
|
if ( now != 67700 )
|
|
print_error("%s(%ld): T%d Error: Set cmp, mc %#lx(%'ld) != %#lx(%'ld)\n",
|
|
__func__, __LINE__, timer, 67752, 67752, now, now);
|
|
cfg = hpet_readl(HPET_Tn_CFG(timer));
|
|
cfg |= HPET_TN_SETVAL;
|
|
hpet_writel(cfg, HPET_Tn_CFG(timer));
|
|
hpet_writel(cmp, HPET_Tn_CMP(timer));
|
|
printf("%s(%ld): HPET_TN_SETVAL cmp=%#lx(%'ld) timer=%d\n",
|
|
__func__, __LINE__, cmp, cmp, timer);
|
|
cmp2 = hpet_readl(HPET_Tn_CMP(timer));
|
|
if ( cmp2 != cmp )
|
|
print_error("%s(%ld): T%d Error: Set cmp, cmp %#lx(%'ld) != %#lx(%'ld)\n",
|
|
__func__, __LINE__, timer, cmp, cmp, cmp2, cmp2);
|
|
|
|
cmp3 = hpet_readl(HPET_Tn_CMP(timer));
|
|
if ( cmp3 != cmp )
|
|
print_error("%s(%ld): T%d Error: Set cmp, cmp %#lx(%'ld) != %#lx(%'ld)\n",
|
|
__func__, __LINE__, timer, cmp, cmp, cmp3, cmp3);
|
|
|
|
if ( dom1.arch.hvm_domain.pl_time.vhpet.hpet.period[timer] != delta )
|
|
printf("%s(%ld): T%d Warning: Set cmp, period %#lx(%'ld) != %#lx(%'ld)\n",
|
|
__func__, __LINE__, timer, delta, delta,
|
|
dom1.arch.hvm_domain.pl_time.vhpet.hpet.period[timer],
|
|
dom1.arch.hvm_domain.pl_time.vhpet.hpet.period[timer]);
|
|
|
|
delta = 500;
|
|
|
|
now = hpet_readl(HPET_COUNTER);
|
|
if ( now != 67700 )
|
|
print_error("%s(%ld): T%d Error: Set period, mc %#lx(%'ld) != %#lx(%'ld)\n",
|
|
__func__, __LINE__, timer, 67752, 67752, now, now);
|
|
cmp2 = hpet_readl(HPET_Tn_CMP(timer));
|
|
if ( cmp2 != cmp )
|
|
print_error("%s(%ld): T%d Error: Set period, cmp %#lx(%'ld) != %#lx(%'ld)\n",
|
|
__func__, __LINE__, timer, cmp, cmp, cmp2, cmp2);
|
|
|
|
hpet_writel((unsigned long) delta, HPET_Tn_CMP(timer));
|
|
printf("%s(%ld): period=%#lx(%'ld) timer=%d\n", __func__, __LINE__,
|
|
(unsigned long) delta, (unsigned long) delta, timer);
|
|
cmp3 = hpet_readl(HPET_Tn_CMP(timer));
|
|
if ( cmp3 != cmp )
|
|
print_error("%s(%ld): T%d Error: Set period, cmp %#lx(%'ld) != %#lx(%'ld)\n",
|
|
__func__, __LINE__, timer, cmp, cmp, cmp3, cmp3);
|
|
|
|
if ( dom1.arch.hvm_domain.pl_time.vhpet.hpet.period[timer] != delta )
|
|
printf("%s(%ld): T%d Warning: Set period, period %#lx(%'ld) != %#lx(%'ld)\n",
|
|
__func__, __LINE__, timer, delta, delta,
|
|
dom1.arch.hvm_domain.pl_time.vhpet.hpet.period[timer],
|
|
dom1.arch.hvm_domain.pl_time.vhpet.hpet.period[timer]);
|
|
|
|
hpet_reset_counter(mc_low, mc_high);
|
|
cfg = hpet_readl(HPET_Tn_CFG(timer));
|
|
cfg |= HPET_TN_SETVAL;
|
|
hpet_writel(cfg, HPET_Tn_CFG(timer));
|
|
hpet_writel(old_cmp, HPET_Tn_CMP(timer));
|
|
hpet_writel(old_delta, HPET_Tn_CMP(timer));
|
|
hpet_start_counter();
|
|
}
|
|
|
|
|
|
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 = 3; 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("%s(%ld): With clock stopped mc64 changed: %'ld to %'ld\n",
|
|
__func__, __LINE__, 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("%s(%ld): With clock stopped mc64 changed: %'ld to %'ld\n",
|
|
__func__, __LINE__, 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("%s(%ld): With clock stopped mc64 changed: %'ld to %'ld\n",
|
|
__func__, __LINE__, 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("%s(%ld): With clock stopped mc64 changed: %'ld to %'ld\n",
|
|
__func__, __LINE__, hpet1.mc64, hpet2.mc64);
|
|
|
|
hpet_set_mode(0xf424, 0);
|
|
hpet_check_stopped(0xf424, 0);
|
|
|
|
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;
|
|
|
|
hpet_set_mode(0, 1);
|
|
hpet_check_stopped(0, 1);
|
|
|
|
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;
|
|
|
|
hpet_set_mode(~0ULL, 2);
|
|
hpet_check_stopped(~0ULL, 2);
|
|
|
|
hpet_set_mode(0x80000000, 2);
|
|
hpet_check_stopped(0x80000000, 2);
|
|
|
|
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:
|
|
*/
|