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