1 /*
2  * Xen emulation for hpet
3  *
4  * Copyright (C) 2014 Verizon Corporation
5  *
6  * This file is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License Version 2 (GPLv2)
8  * as published by the Free Software Foundation.
9  *
10  * This file is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details. <http://www.gnu.org/licenses/>.
14  */
15 
16 /*
17  * http://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/software-developers-hpet-spec-1-0a.pdf
18  *
19  * xen_source is a directory that has all xen source below it.
20  *
21  * Usage:
22  *
23 
24 
25   xen_source=../../..
26   sed -e "/#include/d" -e "1i#include \"emul.h\"\n" <$xen_source/xen/arch/x86/hvm/hpet.c >hpet.c
27   cp $xen_source/xen/include/asm-x86/hpet.h .
28 
29   gcc -g -o test_vhpet hpet.c main.c
30   ./test_vhpet >test_vhpet.out
31 
32  *
33  *
34  * This is almost the same as
35  *
36 
37   make run
38 
39  *
40  * Or
41  *
42  * make -C tools/tests/vhpet run
43  *
44  * From a xen source tree.  The differance
45  * is that you need to be in a xen source tree
46  * and normal make rules apply.
47  *
48  */
49 
50 #define FORCE_THOUSANDS_SEP
51 
52 #include <locale.h>
53 #include <langinfo.h>
54 #include <stdarg.h>
55 #include "emul.h"
56 #include "hpet.h"
57 
58 #define S_TO_NS    1000000000ULL           /* 1s  = 10^9  ns */
59 
60 #define START_MC64 0x108a8
61 
62 static int hpet_mult = 1;
63 static int hpet_add;
64 static int hvm_clock_cost = 1234567;
65 static int tick_count = 1;
66 static int debug = 3;
67 
68 static int skip_load;
69 static int skip_error_on_load;
70 
71 static char *global_thousep;
72 
73 extern const struct hvm_mmio_ops hpet_mmio_ops;
74 
75 struct domain dom1;
76 struct vcpu vcpu0;
77 struct hvm_hw_hpet hpet_save;
78 
79 
80 uint64_t hvm_guest_time;
81 
82 static struct
83 {
84     hvm_save_handler save;
85     hvm_load_handler load;
86     const char *name;
87     size_t size;
88     int kind;
89 } hvm_sr_handlers[3] = {{NULL, NULL, "<?>"},};
90 
91 static uint64_t new_guest_time[] = {
92     0x20,
93     0x2a840,
94     0xf4200,
95     0x10000000000ULL,
96     0x0fffffffffefff00ULL,
97     0x20,
98     0xffffffff00000000ULL,
99     0x20,
100 };
101 
print_error(const char * fmt,...)102 static int print_error(const char *fmt, ...)
103 {
104     va_list args;
105     int i = 0;
106 
107     if ( (debug & 0x0100) && skip_error_on_load )
108         return i;
109 
110     va_start(args, fmt);
111     if ( debug & 0x0001 )
112         i = vfprintf(stdout, fmt, args);
113     va_end(args);
114     va_start(args, fmt);
115     if ( debug & 0x0002 )
116         i = vfprintf(stderr, fmt, args);
117     va_end(args);
118     return i;
119 }
120 
121 
current_domain_id(void)122 int current_domain_id(void)
123 {
124     return current->domain->domain_id;
125 }
126 
get_current()127 struct vcpu *get_current()
128 {
129     return &vcpu0;
130 }
131 
__domain_crash(struct domain * d)132 void __domain_crash(struct domain *d)
133 {
134     exit(42);
135 }
136 
hvm_get_guest_time(struct vcpu * v)137 uint64_t hvm_get_guest_time(struct vcpu *v)
138 {
139     uint64_t ret = hvm_guest_time;
140 
141     hvm_guest_time += hvm_clock_cost;
142     return ret;
143 }
144 
_hvm_init_entry(struct hvm_domain_context * h,uint16_t tc,uint16_t inst,uint32_t len)145 int _hvm_init_entry(struct hvm_domain_context *h,
146                     uint16_t tc, uint16_t inst, uint32_t len)
147 {
148     h->cur = 0;
149     h->size = sizeof(hpet_save);
150     h->data = (void *)&hpet_save;
151 
152     return 0;
153 }
154 
_hvm_check_entry(struct hvm_domain_context * h,uint16_t type,uint32_t len,bool_t strict_length)155 int _hvm_check_entry(struct hvm_domain_context *h,
156                      uint16_t type, uint32_t len, bool_t strict_length)
157 {
158     h->cur = 0;
159     h->size = sizeof(hpet_save);
160     h->data = (void *)&hpet_save;
161 
162     return 0;
163 }
164 
hvm_register_savevm(uint16_t typecode,const char * name,hvm_save_handler save_state,hvm_load_handler load_state,size_t size,int kind)165 void __init hvm_register_savevm(uint16_t typecode,
166                                 const char *name,
167                                 hvm_save_handler save_state,
168                                 hvm_load_handler load_state,
169                                 size_t size, int kind)
170 {
171     hvm_sr_handlers[typecode].save = save_state;
172     hvm_sr_handlers[typecode].load = load_state;
173     hvm_sr_handlers[typecode].name = name;
174     hvm_sr_handlers[typecode].size = size;
175     hvm_sr_handlers[typecode].kind = kind;
176 }
177 
do_save(uint16_t typecode,struct domain * d,hvm_domain_context_t * h)178 int do_save(uint16_t typecode, struct domain *d, hvm_domain_context_t *h)
179 {
180     return hvm_sr_handlers[typecode].save(d, h);
181 }
182 
do_load(uint16_t typecode,struct domain * d,hvm_domain_context_t * h)183 int do_load(uint16_t typecode, struct domain *d, hvm_domain_context_t *h)
184 {
185     if (skip_load & 0x1)
186     {
187         printf("skip_load=%#x\n", skip_load);
188     }
189     else
190     {
191         int ret;
192 
193         printf("do_load\n");
194         skip_error_on_load = 1;
195         ret = hvm_sr_handlers[typecode].load(d, h);
196         skip_error_on_load = 0;
197     }
198 }
199 
dump_hpet(void)200 static void dump_hpet(void)
201 {
202     int i;
203     unsigned long long conf;
204     struct hvm_hw_hpet h = hpet_save;
205     conf = (unsigned long long) h.config;
206     printf("    HPET: capability %#llx config %#llx(%s%s)\n",
207            (unsigned long long) h.capability,
208            conf,
209            conf & HPET_CFG_ENABLE ? "E" : "",
210            conf & HPET_CFG_LEGACY ? "L" : "");
211     printf("          isr %#llx counter %#llx(%'lld)\n",
212            (unsigned long long) h.isr,
213            (unsigned long long) h.mc64,
214            (unsigned long long) h.mc64);
215     for (i = 0; i < HPET_TIMER_NUM; i++)
216     {
217         conf = (unsigned long long) h.timers[i].config;
218         printf("          timer%i config %#llx(%s%s%s) cmp %#llx(%'lld)\n", i,
219                conf,
220                conf & HPET_TN_ENABLE ? "E" : "",
221                conf & HPET_TN_PERIODIC ? "P" : "",
222                conf & HPET_TN_32BIT ? "32" : "",
223                (unsigned long long) h.timers[i].cmp,
224                (unsigned long long) h.timers[i].cmp);
225         printf("          timer%i period %#llx(%'lld) fsb %#llx\n", i,
226                (unsigned long long) h.period[i],
227                (unsigned long long) h.period[i],
228                (unsigned long long) h.timers[i].fsb);
229     }
230 }
231 
pit_stop_channel0_irq(PITState * pit)232 void pit_stop_channel0_irq(PITState *pit)
233 {
234     printf("pit_stop_channel0_irq: pit=%p\n", pit);
235 
236     TRACE_1D(TRC_HVM_VCHIP_PIT_STOP_TIMER, get_cycles());
237     spin_lock(&pit->lock);
238     destroy_periodic_time(&pit->pt0);
239     spin_unlock(&pit->lock);
240 }
241 
destroy_periodic_time(struct periodic_time * pt)242 void destroy_periodic_time(struct periodic_time *pt)
243 {
244     int idx = ((long)pt) & 0x7;
245 
246     printf("destroy_periodic_time: pt=%d\n", idx);
247 }
248 
create_periodic_time(struct vcpu * v,struct periodic_time * pt,uint64_t delta,uint64_t period,uint8_t irq,time_cb * cb,void * data)249 void create_periodic_time(struct vcpu *v, struct periodic_time *pt,
250                           uint64_t delta, uint64_t period, uint8_t irq,
251                           time_cb *cb, void *data)
252 {
253     int idx = ((long)pt) & 0x7;
254 
255     if ( debug & 0x0010 )
256     {
257         int i;
258 
259         printf("create_periodic_time: "
260                "mc64=%#lx(%'ld) mc_offset=%#lx(%'ld)\n",
261                dom1.arch.hvm_domain.pl_time.vhpet.hpet.mc64,
262                dom1.arch.hvm_domain.pl_time.vhpet.hpet.mc64,
263                dom1.arch.hvm_domain.pl_time.vhpet.mc_offset,
264                dom1.arch.hvm_domain.pl_time.vhpet.mc_offset);
265         for (i = 0; i < 3; i++)
266         {
267             printf("                 "
268                    "[%d] cmp64=%#lx(%'ld) cmp=%#lx(%'ld)\n", i,
269                    dom1.arch.hvm_domain.pl_time.vhpet.hpet.comparator64[i],
270                    dom1.arch.hvm_domain.pl_time.vhpet.hpet.comparator64[i],
271                    dom1.arch.hvm_domain.pl_time.vhpet.hpet.timers[i].cmp,
272                    dom1.arch.hvm_domain.pl_time.vhpet.hpet.timers[i].cmp);
273         }
274     }
275     if ( period )
276     {
277         printf("create_periodic_time: pt=%d delta=%'"PRId64" period=%'"PRIu64
278                " - %'"PRIu64".%02d Hz irq=%d\n",
279                idx, delta, period, (uint64_t)(S_TO_NS / period),
280                (int)((S_TO_NS / (period / 100ULL)) % 100), irq);
281         /* +160 is for hpet_tick_to_ns() not simple. */
282         if ( delta > (period * (hpet_mult + hpet_add + 160)) )
283             print_error("%s(%ld): Possible ..MP-BIOS bug: 8254 timer...: delta=%'"PRId64
284                         " period=%'"PRIu64"\n", __func__, __LINE__,
285                         delta, period);
286     }
287     else
288         printf("create_periodic_time: pt=%d delta=%'"PRId64
289                " period=%'"PRIu64" irq=%d\n",
290                idx, delta, period, irq);
291 }
292 
udelay(int w)293 void udelay(int w)
294 {
295 }
296 
hpet_readl(unsigned long a)297 unsigned int hpet_readl(unsigned long a)
298 {
299     unsigned long ret = 0;
300     hpet_mmio_ops.read(current, a, 4, &ret);
301     return ret;
302 }
303 
hpet_writel(unsigned long d,unsigned long a)304 void hpet_writel(unsigned long d, unsigned long a)
305 {
306     hpet_mmio_ops.write(current, a, 4, d);
307     return;
308 }
309 
_hpet_print_config(const char * function,int line)310 static void _hpet_print_config(const char *function, int line)
311 {
312     u32 i, timers, l, h;
313     printk(KERN_INFO "hpet: %s(%d):\n", function, line);
314     l = hpet_readl(HPET_ID);
315     h = hpet_readl(HPET_PERIOD);
316     timers = ((l & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT) + 1;
317     printk(KERN_INFO "hpet: ID: 0x%x, PERIOD: 0x%x\n", l, h);
318     l = hpet_readl(HPET_CFG);
319     h = hpet_readl(HPET_STATUS);
320     printk(KERN_INFO "hpet: CFG: 0x%x, STATUS: 0x%x\n", l, h);
321     l = hpet_readl(HPET_COUNTER);
322     h = hpet_readl(HPET_COUNTER + 4);
323     printk(KERN_INFO "hpet: COUNTER_l: 0x%x, COUNTER_h: 0x%x\n", l, h);
324 
325     for (i = 0; i < timers; i++)
326     {
327         l = hpet_readl(HPET_Tn_CFG(i));
328         h = hpet_readl(HPET_Tn_CFG(i) + 4);
329         printk(KERN_INFO "hpet: T%d: CFG_l: 0x%x, CFG_h: 0x%x\n",
330                i, l, h);
331         l = hpet_readl(HPET_Tn_CMP(i));
332         h = hpet_readl(HPET_Tn_CMP(i) + 4);
333         printk(KERN_INFO "hpet: T%d: CMP_l: 0x%x, CMP_h: 0x%x\n",
334                i, l, h);
335         l = hpet_readl(HPET_Tn_ROUTE(i));
336         h = hpet_readl(HPET_Tn_ROUTE(i) + 4);
337         printk(KERN_INFO "hpet: T%d ROUTE_l: 0x%x, ROUTE_h: 0x%x\n",
338                i, l, h);
339     }
340 }
341 
342 #define hpet_print_config()                     \
343     do {                                        \
344         _hpet_print_config(__func__, __LINE__); \
345     } while ( 0 )
346 
hpet_stop_counter(void)347 static void hpet_stop_counter(void)
348 {
349     unsigned long cfg = hpet_readl(HPET_CFG);
350     cfg &= ~HPET_CFG_ENABLE;
351     hpet_writel(cfg, HPET_CFG);
352 }
353 
hpet_reset_counter(unsigned long low,unsigned long high)354 static void hpet_reset_counter(unsigned long low, unsigned long high)
355 {
356     hpet_writel(low, HPET_COUNTER);
357     hpet_writel(high, HPET_COUNTER + 4);
358 }
359 
hpet_start_counter(void)360 static void hpet_start_counter(void)
361 {
362     unsigned long cfg = hpet_readl(HPET_CFG);
363     cfg |= HPET_CFG_ENABLE;
364     hpet_writel(cfg, HPET_CFG);
365 }
366 
hpet_restart_counter(void)367 static void hpet_restart_counter(void)
368 {
369     hpet_stop_counter();
370     hpet_reset_counter(0, 0);
371     hpet_start_counter();
372 }
373 
hpet_set_mode(uint64_t delta,int timer)374 static void hpet_set_mode(uint64_t delta, int timer)
375 {
376     unsigned long cfg, cmp, cmp2, now;
377 
378     hpet_stop_counter();
379     now = hpet_readl(HPET_COUNTER);
380     cmp = now + (unsigned long)(hpet_mult * delta) + hpet_add;
381     cfg = hpet_readl(HPET_Tn_CFG(timer));
382     /* Make sure we use edge triggered interrupts */
383     cfg &= ~HPET_TN_LEVEL;
384     cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC |
385            HPET_TN_SETVAL | HPET_TN_32BIT;
386     /* Mask to 32 bits just like the hardware */
387     cmp = (uint32_t)cmp;
388     delta = (uint32_t)delta;
389     /* Do the config */
390     hpet_writel(cfg, HPET_Tn_CFG(timer));
391     hpet_writel(cmp, HPET_Tn_CMP(timer));
392     printf("%s(%ld): HPET_TN_SETVAL cmp=%#lx(%'ld) timer=%d\n",
393            __func__, __LINE__, cmp, cmp, timer);
394     udelay(1);
395     /*
396      * HPET on AMD 81xx needs a second write (with HPET_TN_SETVAL
397      * cleared) to T0_CMP to set the period. The HPET_TN_SETVAL
398      * bit is automatically cleared after the first write.
399      * (See AMD-8111 HyperTransport I/O Hub Data Sheet,
400      * Publication # 24674)
401      */
402     hpet_writel((unsigned long) delta, HPET_Tn_CMP(timer));
403     printf("%s(%ld): period=%#lx(%'ld) timer=%d\n", __func__, __LINE__,
404            (unsigned long) delta, (unsigned long) delta, timer);
405     cmp2 = hpet_readl(HPET_Tn_CMP(timer));
406     if ( cmp2 != cmp )
407         print_error("%s(%ld): T%d Error: Set %#lx(%'ld) != %#lx(%'ld)\n",
408                     __func__, __LINE__, timer, cmp, cmp, cmp2, cmp2);
409 
410     hpet_start_counter();
411     hpet_print_config();
412 }
413 
414 
hpet_check_stopped(uint64_t old_delta,int timer)415 hpet_check_stopped(uint64_t old_delta, int timer)
416 {
417     unsigned long mc_low, mc_high, old_cmp, now;
418     unsigned long cfg, cmp, delta, cmp2, cmp3;
419 
420     if (skip_load & 0x2)
421     {
422         printf("Skip hpet_check_stopped. skip_load=%#x\n", skip_load);
423         return;
424     }
425     hpet_stop_counter();
426     mc_low = hpet_readl(HPET_COUNTER);
427     mc_high = hpet_readl(HPET_COUNTER + 4);
428     old_cmp = hpet_readl(HPET_Tn_CMP(timer));
429 
430     hpet_reset_counter(67752, 0);
431     cmp = 255252;
432     delta = 62500;
433 
434     now = hpet_readl(HPET_COUNTER);
435     if ( now != 67752 )
436         print_error("%s(%ld): T%d Error: Set mc %#lx(%'ld) != %#lx(%'ld)\n",
437                     __func__, __LINE__, timer, 67752, 67752, now, now);
438     cfg = hpet_readl(HPET_Tn_CFG(timer));
439     cfg |= HPET_TN_SETVAL;
440     hpet_writel(cfg, HPET_Tn_CFG(timer));
441     hpet_writel(cmp, HPET_Tn_CMP(timer));
442     printf("%s(%ld): HPET_TN_SETVAL cmp=%#lx(%'ld) timer=%d\n",
443            __func__, __LINE__, cmp, cmp, timer);
444     cmp2 = hpet_readl(HPET_Tn_CMP(timer));
445     if ( cmp2 != cmp )
446         print_error("%s(%ld): T%d Error: Set cmp %#lx(%'ld) != %#lx(%'ld)\n",
447                     __func__, __LINE__, timer, cmp, cmp, cmp2, cmp2);
448 
449     hpet_writel((unsigned long) delta, HPET_Tn_CMP(timer));
450     printf("%s(%ld): period=%#lx(%'ld) timer=%d\n", __func__, __LINE__,
451            (unsigned long) delta, (unsigned long) delta, timer);
452     cmp3 = hpet_readl(HPET_Tn_CMP(timer));
453     if ( cmp3 != cmp )
454         print_error("%s(%ld): T%d Error: Set period, cmp %#lx(%'ld) != %#lx(%'ld)\n",
455                     __func__, __LINE__, timer, cmp, cmp, cmp3, cmp3);
456 
457     if ( dom1.arch.hvm_domain.pl_time.vhpet.hpet.period[timer] != delta )
458         printf("%s(%ld): T%d Warning: Set period %#lx(%'ld) != %#lx(%'ld)\n",
459                __func__, __LINE__, timer, delta, delta,
460                dom1.arch.hvm_domain.pl_time.vhpet.hpet.period[timer],
461                dom1.arch.hvm_domain.pl_time.vhpet.hpet.period[timer]);
462 
463     hpet_reset_counter(67752, 0);
464     cmp = 255252;
465     delta = 62500;
466 
467     now = hpet_readl(HPET_COUNTER);
468     if ( now != 67752 )
469         print_error("%s(%ld): T%d Error: Set mc %#lx(%'ld) != %#lx(%'ld)\n",
470                     __func__, __LINE__, timer, 67752, 67752, now, now);
471     cfg = hpet_readl(HPET_Tn_CFG(timer));
472     cfg |= HPET_TN_SETVAL;
473     hpet_writel(cfg, HPET_Tn_CFG(timer));
474     hpet_writel(cmp, HPET_Tn_CMP(timer));
475     printf("%s(%ld): HPET_TN_SETVAL cmp=%#lx(%'ld) timer=%d\n",
476            __func__, __LINE__, cmp, cmp, timer);
477     cmp2 = hpet_readl(HPET_Tn_CMP(timer));
478     if ( cmp2 != cmp )
479         print_error("%s(%ld): T%d Error: Set cmp %#lx(%'ld) != %#lx(%'ld)\n",
480                     __func__, __LINE__, timer, cmp, cmp, cmp2, cmp2);
481 
482     hpet_writel((unsigned long) delta, HPET_Tn_CMP(timer));
483     printf("%s(%ld): period=%#lx(%'ld) timer=%d\n", __func__, __LINE__,
484            (unsigned long) delta, (unsigned long) delta, timer);
485     cmp3 = hpet_readl(HPET_Tn_CMP(timer));
486     if ( cmp3 != cmp )
487         print_error("%s(%ld): T%d Error: Set period, cmp %#lx(%'ld) != %#lx(%'ld)\n",
488                     __func__, __LINE__, timer, cmp, cmp, cmp3, cmp3);
489 
490     if ( dom1.arch.hvm_domain.pl_time.vhpet.hpet.period[timer] != delta )
491         printf("%s(%ld): T%d Warning: Set period %#lx(%'ld) != %#lx(%'ld)\n",
492                __func__, __LINE__, timer, delta, delta,
493                dom1.arch.hvm_domain.pl_time.vhpet.hpet.period[timer],
494                dom1.arch.hvm_domain.pl_time.vhpet.hpet.period[timer]);
495 
496     hpet_reset_counter(67700, 0);
497 
498     now = hpet_readl(HPET_COUNTER);
499     if ( now != 67700 )
500         print_error("%s(%ld): T%d Error: Set mc %#lx(%'ld) != %#lx(%'ld)\n",
501                     __func__, __LINE__, timer, 67752, 67752, now, now);
502     cmp2 = hpet_readl(HPET_Tn_CMP(timer));
503     if ( cmp2 != cmp )
504         print_error("%s(%ld): T%d Error: Set mc, cmp %#lx(%'ld) != %#lx(%'ld)\n",
505                     __func__, __LINE__, timer, cmp, cmp, cmp2, cmp2);
506 
507     cmp3 = hpet_readl(HPET_Tn_CMP(timer));
508     if ( cmp3 != cmp )
509         print_error("%s(%ld): T%d Error: Set mc, cmp %#lx(%'ld) != %#lx(%'ld)\n",
510                     __func__, __LINE__, timer, cmp, cmp, cmp3, cmp3);
511 
512     if ( dom1.arch.hvm_domain.pl_time.vhpet.hpet.period[timer] != delta )
513         printf("%s(%ld): T%d Warning: Set mc, period %#lx(%'ld) != %#lx(%'ld)\n",
514                __func__, __LINE__, timer, delta, delta,
515                dom1.arch.hvm_domain.pl_time.vhpet.hpet.period[timer],
516                dom1.arch.hvm_domain.pl_time.vhpet.hpet.period[timer]);
517 
518     cmp = 67701;
519 
520     now = hpet_readl(HPET_COUNTER);
521     if ( now != 67700 )
522         print_error("%s(%ld): T%d Error: Set cmp, mc %#lx(%'ld) != %#lx(%'ld)\n",
523                     __func__, __LINE__, timer, 67752, 67752, now, now);
524     cfg = hpet_readl(HPET_Tn_CFG(timer));
525     cfg |= HPET_TN_SETVAL;
526     hpet_writel(cfg, HPET_Tn_CFG(timer));
527     hpet_writel(cmp, HPET_Tn_CMP(timer));
528     printf("%s(%ld): HPET_TN_SETVAL cmp=%#lx(%'ld) timer=%d\n",
529            __func__, __LINE__, cmp, cmp, timer);
530     cmp2 = hpet_readl(HPET_Tn_CMP(timer));
531     if ( cmp2 != cmp )
532         print_error("%s(%ld): T%d Error: Set cmp, cmp %#lx(%'ld) != %#lx(%'ld)\n",
533                     __func__, __LINE__, timer, cmp, cmp, cmp2, cmp2);
534 
535     cmp3 = hpet_readl(HPET_Tn_CMP(timer));
536     if ( cmp3 != cmp )
537         print_error("%s(%ld): T%d Error: Set cmp, cmp %#lx(%'ld) != %#lx(%'ld)\n",
538                     __func__, __LINE__, timer, cmp, cmp, cmp3, cmp3);
539 
540     if ( dom1.arch.hvm_domain.pl_time.vhpet.hpet.period[timer] != delta )
541         printf("%s(%ld): T%d Warning: Set cmp, period %#lx(%'ld) != %#lx(%'ld)\n",
542                __func__, __LINE__, timer, delta, delta,
543                dom1.arch.hvm_domain.pl_time.vhpet.hpet.period[timer],
544                dom1.arch.hvm_domain.pl_time.vhpet.hpet.period[timer]);
545 
546     delta = 500;
547 
548     now = hpet_readl(HPET_COUNTER);
549     if ( now != 67700 )
550         print_error("%s(%ld): T%d Error: Set period, mc %#lx(%'ld) != %#lx(%'ld)\n",
551                     __func__, __LINE__, timer, 67752, 67752, now, now);
552     cmp2 = hpet_readl(HPET_Tn_CMP(timer));
553     if ( cmp2 != cmp )
554         print_error("%s(%ld): T%d Error: Set period, cmp %#lx(%'ld) != %#lx(%'ld)\n",
555                     __func__, __LINE__, timer, cmp, cmp, cmp2, cmp2);
556 
557     hpet_writel((unsigned long) delta, HPET_Tn_CMP(timer));
558     printf("%s(%ld): period=%#lx(%'ld) timer=%d\n", __func__, __LINE__,
559            (unsigned long) delta, (unsigned long) delta, timer);
560     cmp3 = hpet_readl(HPET_Tn_CMP(timer));
561     if ( cmp3 != cmp )
562         print_error("%s(%ld): T%d Error: Set period, cmp %#lx(%'ld) != %#lx(%'ld)\n",
563                     __func__, __LINE__, timer, cmp, cmp, cmp3, cmp3);
564 
565     if ( dom1.arch.hvm_domain.pl_time.vhpet.hpet.period[timer] != delta )
566         printf("%s(%ld): T%d Warning: Set period, period %#lx(%'ld) != %#lx(%'ld)\n",
567                __func__, __LINE__, timer, delta, delta,
568                dom1.arch.hvm_domain.pl_time.vhpet.hpet.period[timer],
569                dom1.arch.hvm_domain.pl_time.vhpet.hpet.period[timer]);
570 
571     hpet_reset_counter(mc_low, mc_high);
572     cfg = hpet_readl(HPET_Tn_CFG(timer));
573     cfg |= HPET_TN_SETVAL;
574     hpet_writel(cfg, HPET_Tn_CFG(timer));
575     hpet_writel(old_cmp, HPET_Tn_CMP(timer));
576     hpet_writel(old_delta, HPET_Tn_CMP(timer));
577     hpet_start_counter();
578 }
579 
580 
581 int
main(int argc,char ** argv)582 main(int argc, char **argv)
583 {
584     hvm_domain_context_t hdc;
585     struct hvm_hw_hpet hpet0;
586     struct hvm_hw_hpet hpet1;
587     struct hvm_hw_hpet hpet2;
588     int i, k;
589 
590     setlocale(LC_ALL, "");
591 
592 #ifdef FORCE_THOUSANDS_SEP
593     setlocale(LC_NUMERIC, "en_US.utf8");
594 #endif
595     global_thousep = nl_langinfo(THOUSEP);
596 
597     printf("test_vhpet 1.0\n");
598 
599     if ( argc > 1 )
600         hvm_clock_cost = atoi(argv[1]);
601     if ( argc > 2 )
602         hpet_mult = atoi(argv[2]);
603     if ( argc > 3 )
604         hpet_add = atoi(argv[3]);
605     if ( argc > 4 )
606         tick_count = atoi(argv[4]);
607     if ( argc > 5 )
608         debug = strtol(argv[5], NULL, 0);
609 
610     printf("hvm_clock_cost=%'d hpet_mult=%'d hpet_add=%'d tick_count=%d debug=%#x\n",
611            hvm_clock_cost, hpet_mult, hpet_add, tick_count, debug);
612 
613     dom1.domain_id = 1;
614     dom1.vcpu[0] = &vcpu0;
615     vcpu0.vcpu_id = 0;
616     vcpu0.domain = &dom1;
617 
618     __hvm_register_HPET_save_and_restore();
619 
620     for (skip_load = 3; skip_load >= 0; skip_load--)
621     {
622 
623         printf("\nskip_load=%d\n", skip_load);
624 
625         hvm_guest_time = 16;
626 
627         hpet_init(&vcpu0);
628 
629         do_save(HVM_SAVE_CODE(HPET), &dom1, &hdc);
630         dump_hpet();
631         hpet0 = hpet_save;
632         do_save(HVM_SAVE_CODE(HPET), &dom1, &hdc);
633         dump_hpet();
634         hpet1 = hpet_save;
635         if (hpet0.mc64 != hpet1.mc64)
636             print_error("%s(%ld): With clock stopped mc64 changed: %'ld to %'ld\n",
637                         __func__, __LINE__, hpet0.mc64, hpet1.mc64);
638 
639         do_load(HVM_SAVE_CODE(HPET), &dom1, &hdc);
640         do_save(HVM_SAVE_CODE(HPET), &dom1, &hdc);
641         dump_hpet();
642         hpet2 = hpet_save;
643         if (hpet1.mc64 != hpet2.mc64)
644             print_error("%s(%ld): With clock stopped mc64 changed: %'ld to %'ld\n",
645                         __func__, __LINE__, hpet1.mc64, hpet2.mc64);
646 
647         dom1.arch.hvm_domain.pl_time.vhpet.hpet.mc64 = START_MC64;
648         dom1.arch.hvm_domain.pl_time.vhpet.mc_offset = START_MC64
649             - hvm_guest_time - hvm_clock_cost;
650         printf("\n"
651                "mc64=%#lx(%'ld) mc_offset=%#lx(%'ld)\n",
652                dom1.arch.hvm_domain.pl_time.vhpet.hpet.mc64,
653                dom1.arch.hvm_domain.pl_time.vhpet.hpet.mc64,
654                dom1.arch.hvm_domain.pl_time.vhpet.mc_offset,
655                dom1.arch.hvm_domain.pl_time.vhpet.mc_offset);
656 
657         printf("\nhvm_guest_time=%#lx(%'ld)\n",
658                hvm_guest_time, hvm_guest_time);
659 
660         do_save(HVM_SAVE_CODE(HPET), &dom1, &hdc);
661         dump_hpet();
662         hpet0 = hpet_save;
663         do_save(HVM_SAVE_CODE(HPET), &dom1, &hdc);
664         dump_hpet();
665         hpet1 = hpet_save;
666         if (hpet0.mc64 != hpet1.mc64)
667             print_error("%s(%ld): With clock stopped mc64 changed: %'ld to %'ld\n",
668                         __func__, __LINE__, hpet0.mc64, hpet1.mc64);
669 
670         do_load(HVM_SAVE_CODE(HPET), &dom1, &hdc);
671         do_save(HVM_SAVE_CODE(HPET), &dom1, &hdc);
672         dump_hpet();
673         hpet2 = hpet_save;
674         if (hpet1.mc64 != hpet2.mc64)
675             print_error("%s(%ld): With clock stopped mc64 changed: %'ld to %'ld\n",
676                         __func__, __LINE__, hpet1.mc64, hpet2.mc64);
677 
678         hpet_set_mode(0xf424, 0);
679         hpet_check_stopped(0xf424, 0);
680 
681         do_save(HVM_SAVE_CODE(HPET), &dom1, &hdc);
682         dump_hpet();
683         hpet0 = hpet_save;
684         do_save(HVM_SAVE_CODE(HPET), &dom1, &hdc);
685         dump_hpet();
686         hpet1 = hpet_save;
687         do_load(HVM_SAVE_CODE(HPET), &dom1, &hdc);
688         do_save(HVM_SAVE_CODE(HPET), &dom1, &hdc);
689         dump_hpet();
690         hpet2 = hpet_save;
691 
692         hpet_set_mode(0, 1);
693         hpet_check_stopped(0, 1);
694 
695         do_save(HVM_SAVE_CODE(HPET), &dom1, &hdc);
696         dump_hpet();
697         hpet0 = hpet_save;
698         do_save(HVM_SAVE_CODE(HPET), &dom1, &hdc);
699         dump_hpet();
700         hpet1 = hpet_save;
701 
702         do_load(HVM_SAVE_CODE(HPET), &dom1, &hdc);
703         do_save(HVM_SAVE_CODE(HPET), &dom1, &hdc);
704         dump_hpet();
705         hpet2 = hpet_save;
706 
707         hpet_set_mode(~0ULL, 2);
708         hpet_check_stopped(~0ULL, 2);
709 
710         hpet_set_mode(0x80000000, 2);
711         hpet_check_stopped(0x80000000, 2);
712 
713         do_save(HVM_SAVE_CODE(HPET), &dom1, &hdc);
714         dump_hpet();
715         hpet0 = hpet_save;
716         do_save(HVM_SAVE_CODE(HPET), &dom1, &hdc);
717         dump_hpet();
718         hpet1 = hpet_save;
719 
720         do_load(HVM_SAVE_CODE(HPET), &dom1, &hdc);
721         do_save(HVM_SAVE_CODE(HPET), &dom1, &hdc);
722         dump_hpet();
723         hpet2 = hpet_save;
724 
725 
726         for (k = 0; k < ARRAY_SIZE(new_guest_time); k++)
727         {
728             hvm_guest_time = new_guest_time[k];
729             printf("\nhvm_guest_time=%#lx(%'ld)\n",
730                    hvm_guest_time, hvm_guest_time);
731 
732             do_save(HVM_SAVE_CODE(HPET), &dom1, &hdc);
733             dump_hpet();
734             hpet0 = hpet_save;
735             do_save(HVM_SAVE_CODE(HPET), &dom1, &hdc);
736             dump_hpet();
737             hpet1 = hpet_save;
738 
739             do_load(HVM_SAVE_CODE(HPET), &dom1, &hdc);
740             do_save(HVM_SAVE_CODE(HPET), &dom1, &hdc);
741             dump_hpet();
742             hpet2 = hpet_save;
743 
744             for (i = 0; i < tick_count; i++)
745             {
746                 hvm_guest_time += 0x10;
747                 printf("\nhvm_guest_time=%#lx(%'ld)\n",
748                        hvm_guest_time, hvm_guest_time);
749 
750                 do_save(HVM_SAVE_CODE(HPET), &dom1, &hdc);
751                 dump_hpet();
752                 hpet0 = hpet_save;
753                 do_save(HVM_SAVE_CODE(HPET), &dom1, &hdc);
754                 dump_hpet();
755                 hpet1 = hpet_save;
756 
757                 do_load(HVM_SAVE_CODE(HPET), &dom1, &hdc);
758                 do_save(HVM_SAVE_CODE(HPET), &dom1, &hdc);
759                 dump_hpet();
760                 hpet2 = hpet_save;
761 
762             }
763         }
764     }
765 
766     return 0;
767 }
768 
769 /*
770  * Local variables:
771  * mode: C
772  * c-file-style: "BSD"
773  * c-basic-offset: 4
774  * indent-tabs-mode: nil
775  * End:
776  */
777