Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


5e65cd9b65b8407538466c88671dba2d018c5af9
[palacios.git] / palacios / src / devices / hpet.c
1 /* 
2  * This file is part of the Palacios Virtual Machine Monitor developed
3  * by the V3VEE Project with funding from the United States National 
4  * Science Foundation and the Department of Energy.  
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at 
8  * http://www.v3vee.org
9  *
10  * Copyright (c) 2014, Kyle C. Hale <kh@u.northwestern.edu>
11  * Copyright (c) 2014, The V3VEE Project <http://www.v3vee.org> 
12  * All rights reserved.
13  *
14  * Authors: Kyle C. Hale <kh@u.northwestern.edu>
15  *         
16  * Emulated HPET device
17  *
18  * This is free software.  You are permitted to use,
19  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
20  */
21
22 #include <palacios/vmm.h>
23 #include <palacios/vm_guest.h>
24 #include <palacios/vmm_types.h>
25 #include <palacios/vmm_queue.h>
26 #include <palacios/vmm_lock.h>
27 #include <palacios/vmm_debug.h>
28
29
30 #ifndef V3_CONFIG_DEBUG_HPET
31 #undef PrintDebug
32 #define PrintDebug(fmt, args...)
33 #endif
34
35
36 #define HPET_REGION_SIZE       1024
37 #define HPET_DEFAULT_BASE_ADDR 0xFED00000ULL
38 #define HPET_NUM_TIMERS        3
39 #define V3_VENDOR              0xA333
40 #define NANOSECS               1000000000ULL          
41 #define FEMTOSECS              1000000000000000ULL     
42
43 #define HPET_TIMER_INT_ROUTE_CAP_SHIFT 32
44 /* HPET irqs can be routed to IOAPIC [23..20] */
45 #define HPET_TIMER_INT_ROUTE_CAP      (0x00f00000ULL \ << HPET_TIMER_INT_ROUTE_CAP_SHIFT)
46
47 /* Memory-Mapped Register Offsets */
48 #define GEN_CAP_REG_OFFSET       0x000 // r
49 #define RSVD_OFFSET              0x008
50 #define GEN_CFG_REG_OFFSET       0x010 // rw
51 #define RSVD_OFFSET1             0x018
52 #define GEN_ISR_OFFSET           0x020 // rw clear
53 #define RSVD_OFFSET2             0x028
54 #define MAIN_CNTR_VAL_REG_OFFSET 0x0F0 // rw
55 #define RSVD_OFFSET3             0x0F8
56 #define RSVD_OFFSET4             0x118
57 #define RSVD_OFFSET5             0x138
58 #define RSVD_OFFSET6             0x158
59 #define RSVD_3_31_OFFSET         0x160
60 #define TIMER_N_OFFSET_CFG(n)     (0x100 + (n) * 0x20) // rw
61 #define TIMER_N_OFFSET_CMP(n)     (0x108 + (n) * 0x20) // rw
62 #define TIMER_N_OFFSET_FSB_IRR(n) (0x110 + (n) * 0x20) // rw
63
64 /* extract an architectural field for timer N */
65 #define TIMER_N(f, addr) (((addr) - TIMER_N_OFFSET_##f(0)) / (TIMER_N_OFFSET_##f(1) - TIMER_N_OFFSET_##f(0)))
66
67 /* utility macros */
68 #define is_hpet_enabled(hpet)         (hpet->regs.cfg.enable_cnf)
69
70 /* timer-specific utility macros */
71 #define in_periodic_mode(hpet, n)     (hpet->regs.timers[n].caps.tn_type_cnf)
72 #define timer_32bit(hpet, n)          (hpet->regs.timers[n].caps.tn_32mode_cnf)
73 #define is_timer_enabled(hpet, n)     (hpet->regs.timers[n].caps.tn_int_enb_cnf)
74 #define is_timer_ltrig(hpet, n)       (hpet->regs.timers[n].caps.tn_int_type_cnf)
75 #define set_timer_bit(x, n)           ((x) |= (1UL << (n)))
76 #define unset_timer_bit(x, n)         ((x) &= (~(1UL << (n))))
77
78 /* flag macros */
79 #define HPET_CFG_ENABLE 0x001
80 #define HPET_CFG_LEGACY 0x002
81 #define HPET_LEGACY_8254    2
82 #define HPET_LEGACY_RTC     8
83
84 #define HPET_TIMER_LEVEL       0x002
85 #define HPET_TIMER_ENABLE      0x004
86 #define HPET_TIMER_PERIODIC    0x008
87 #define HPET_TIMER_PERIODIC_CAP    0x010
88 #define HPET_TIMER_64BIT_CAP   0x020
89 #define HPET_TIMER_SETVAL      0x040
90 #define HPET_TIMER_32BIT       0x100
91 #define HPET_TIMER_ROUTE       0x3e00
92 #define HPET_TIMER_FSB     0x4000
93 #define HPET_TIMER_FSB_CAP     0x8000
94 #define HPET_TIMER_RESERVED    0xffff0081
95 #define HPET_TIMER_ROUTE_SHIFT 9
96
97 /* we're going to set the HPET timer freq. to be 1/16th rate of Palacios system time */
98 #define HPET_PERIOD 16   
99
100 #define SYS_TICKS_PER_NS(hpet)       ((hpet)->system_freq/NANOSECS)
101 #define hpet_guest_time(hpet)        (v3_get_guest_time(&(hpet)->core->time_state) / (HPET_PERIOD*SYS_TICKS_PER_NS(hpet)))
102 #define HPET_SMALL_WINDOW(hpet)      (((hpet)->system_freq >> 10) / HPET_PERIOD)
103
104 #define tick_to_ns(hpet, tick)                  \
105          (((((tick) > (hpet)->max_ns_res) ?     \
106          ~0ULL : (tick) * (hpet)->ns_per_tick) >> 10))
107
108
109 /* General Capabilities and ID Register */
110 struct hpet_cap_reg {
111     union {
112         uint64_t value;
113         struct {
114             uint8_t rev_id;
115             uint8_t num_tim_cap    : 5;
116             uint8_t count_size_cap : 1;
117             uint8_t rsvd           : 1;
118             uint8_t leg_route_cap  : 1;
119             uint16_t vendor_id;
120             uint32_t counter_clk_period; 
121         } __attribute__((packed));
122     } __attribute__((packed));
123 } __attribute__((packed));
124
125
126 /* General Configuration Register */
127 struct hpet_gen_cfg_reg {
128     union {
129         uint64_t value;
130         struct {
131             uint8_t enable_cnf : 1;
132             uint8_t leg_rt_cnf : 1;
133             uint8_t rsvd       : 6;
134             uint8_t rsvd2;
135             uint64_t rsvd3     : 48;
136         } __attribute__((packed));
137     } __attribute__((packed));
138 } __attribute__((packed));
139
140
141 /* General Interrupt Status Register */
142 struct hpet_gen_irq_status_reg {
143     union {
144         uint64_t value;
145         struct {
146             uint8_t t0_int_sts : 1;
147             uint8_t t1_int_sts : 1;
148             uint8_t t2_int_sts : 1;
149             uint32_t rsvd      : 29;
150             uint32_t rsvd2;
151         } __attribute__((packed));
152     } __attribute__((packed));
153 } __attribute__((packed));
154
155 /* Timer N Configuration and Capabilities Register */
156 struct timer_cfg_cap_reg {
157     union {
158         uint64_t value;
159         struct {
160             uint8_t rsvd : 1;
161             uint8_t tn_int_type_cnf    : 1;
162             uint8_t tn_int_enb_cnf     : 1;
163             uint8_t tn_type_cnf        : 1;
164             uint8_t tn_per_int_cap     : 1;
165             uint8_t tn_size_cap        : 1;
166             uint8_t tn_val_set_cnf     : 1;
167             uint8_t rsvd2              : 1;
168             uint8_t tn_32mode_cnf      : 1;
169             uint8_t tn_int_route_cnf   : 5;
170             uint8_t tn_fsb_en_cnf      : 1;
171             uint8_t tn_fsb_int_del_cap : 1;
172             uint16_t rsvd3;
173             uint32_t tn_int_route_cap;
174         } __attribute__((packed));
175     } __attribute__((packed));
176 } __attribute__((packed));
177
178
179 /* Timer N Comparator Register */
180 struct timer_comp_reg {
181     union {
182         uint64_t value;
183         struct {
184             uint32_t lo;
185             uint32_t hi;
186         } __attribute__((packed));
187     } __attribute__((packed));
188 } __attribute__((packed));
189
190 /* 
191  * Timer N FSB Interrupt Route Reigster
192  *
193  * not supported 
194  */
195 struct timer_fsb_int_route_reg {
196     union {
197         uint64_t value;
198         struct {
199             uint32_t tn_fsb_int_val;
200             uint32_t tn_fsb_int_addr;
201         } __attribute__((packed));
202     } __attribute__((packed));
203 } __attribute__((packed));
204
205
206 /* architectural state for timer N */
207 struct timer_regs {
208     struct timer_cfg_cap_reg       caps;
209     struct timer_comp_reg          comp;
210     struct timer_fsb_int_route_reg fsb_int_route; // not supported
211     uint64_t                       rsvd;
212 } __attribute__((packed));
213
214
215 /* hidden state for timer N */
216 struct hpet_timer_state {
217     uint_t              timer_num; 
218     uint_t              oneshot;
219     uint_t              irq;
220     struct hpet_state * hpet;
221     struct v3_timer *   timer;
222 };
223
224
225 struct hpet_state {
226
227     /* archietected registers */
228     union {
229        uint32_t raw_regs[HPET_REGION_SIZE/4]; // 1K total is mapped in
230        struct {
231
232           /* memory mapped registers */
233           struct hpet_cap_reg            caps;                    // 0x000
234           uint64_t                       rsvd1;                   // 0x008
235           struct hpet_gen_cfg_reg        cfg;                     // 0x010
236           uint64_t                       rsvd2;                   // 0x018
237           struct hpet_gen_irq_status_reg irq_status;              // 0x020
238           uint64_t                       rsvd3[50];               // 0x028
239           uint64_t                       main_counter;            // 0x0f0
240           uint64_t                       rsvd4;                   // 0x0f8
241           struct timer_regs              timers[HPET_NUM_TIMERS]; // 0x100, 0x120, etc.
242
243        } __attribute__((packed)) regs;
244     } __attribute__((packed));
245
246     /* hidden state */
247     addr_t                  base_addr;
248     uint64_t                counter_offset;
249     struct guest_info *     core;
250     struct hpet_timer_state timer_states[HPET_NUM_TIMERS];
251     v3_lock_t               lock;
252
253     /* time-keeping */
254     uint64_t                system_freq; 
255     uint64_t                ns_per_tick; // how many nanosecs per HPET tick
256     uint64_t                max_ns_res;  // max number of ticks we can rep in nanosec */
257
258     /* this is the initial value written to the comparator 
259      * for periodic timers, we increment the comparator by this 
260      * many ticks after raising each irq 
261      */
262     uint64_t period[HPET_NUM_TIMERS]; 
263
264     /*
265      * shadow comparator
266      * for each timer, we compare the main counter
267      * against this. when it matches, raise irq 
268      */
269     uint64_t comparator[HPET_NUM_TIMERS];
270
271 };
272
273
274 static int hpet_read (struct guest_info * core, addr_t guest_addr, void * dst, uint_t length, void * priv_data);
275 static int hpet_write (struct guest_info * core, addr_t guest_addr, void * src, uint_t length, void * priv_data);
276
277
278 /* return first set bit */
279 static inline unsigned int 
280 first_bit (unsigned long x)
281 {
282     __asm__ __volatile__ ("bsf %1,%0" : "=r" (x) : "r" (x));
283     return (unsigned int)x;
284 }
285
286
287 static void
288 remove_hpet_timers (struct hpet_state * hpet) 
289 {
290     int i;
291
292     for (i = 0; i < HPET_NUM_TIMERS; i++) {
293         if (hpet->timer_states[i].timer) {
294             v3_remove_timer(hpet->core, hpet->timer_states[i].timer);
295             hpet->timer_states[i].timer = NULL;
296         }
297     }
298 }
299
300
301 /* make sure accesses don't go across register boundaries */
302 static inline int 
303 check_hpet_access (struct guest_info * core, addr_t guest_addr, uint_t length) 
304 {
305     /* is access aligned to the access length? */
306     if (guest_addr & (--length) || length > 8) {
307         PrintError(core->vm_info, core, "HPET: access across register boundary\n");
308         return -1;
309     }
310     return 0;
311 }
312
313
314 /* get the value that we should return when main counter is read */
315 static inline uint64_t 
316 read_hpet_counter (struct hpet_state * hpet) 
317
318     if (is_hpet_enabled(hpet)) {
319         return hpet_guest_time(hpet) + hpet->counter_offset;
320     } else {
321         return hpet->regs.main_counter;
322     }
323
324 }
325
326
327 /* return the *most recent* comparator value 
328  * as a side-effect, the comparator for timer N is
329  * updated to reflect any missed timer interrupts */
330 static uint64_t 
331 read_hpet_comparator (struct hpet_state * hpet, unsigned int timer_n) 
332 {
333     uint64_t comp;
334     uint64_t elapsed;
335
336     comp = hpet->comparator[timer_n];
337     
338     if (in_periodic_mode(hpet, timer_n)) {
339         // advance comp by # of periods since last update
340         uint64_t period = hpet->period[timer_n];
341         if (period) {
342             elapsed = read_hpet_counter(hpet) + period - 1 - comp;
343             comp += (elapsed / period) * period;
344             hpet->comparator[timer_n] = comp;
345         }
346     }
347
348     // if we're in 32-bit mode, truncate
349     if (timer_32bit(hpet, timer_n)) {
350         comp = (uint32_t)comp;
351     }
352
353     hpet->regs.timers[timer_n].comp.value = comp;
354     return comp;
355 }
356
357
358 static void 
359 init_hpet_state (struct hpet_state * hpet) 
360 {
361     int i;
362
363     hpet->base_addr = HPET_DEFAULT_BASE_ADDR;
364
365     memset(hpet->raw_regs, 0, HPET_REGION_SIZE);
366
367     hpet->regs.caps.rev_id             = 1; // must be non-zero
368     hpet->regs.caps.num_tim_cap        = HPET_NUM_TIMERS - 1;
369     hpet->regs.caps.count_size_cap     = 1; // 64-bit mode
370     hpet->regs.caps.leg_route_cap      = 1; // we support legacy interrupt routing
371     hpet->regs.caps.vendor_id          = V3_VENDOR;
372
373     // # of femtosecs per HPET tick, HPET frequency is 1/16th of palacios time
374     hpet->regs.caps.counter_clk_period = FEMTOSECS*HPET_PERIOD/hpet->system_freq;
375
376     // timer-specific archictectural state 
377     for (i = 0; i < HPET_NUM_TIMERS; i++) {
378             hpet->regs.timers[i].caps.tn_int_route_cap = HPET_TIMER_INT_ROUTE_CAP_SHIFT; // we support routing through the IOAPIC
379             hpet->regs.timers[i].caps.tn_size_cap      = 1; // 64-bit
380             hpet->regs.timers[i].caps.tn_per_int_cap   = 1; // this timer supports periodic mode
381             hpet->regs.timers[i].comp.value            = ~0ULL; // initial value for comparator: default value should be all 1's
382     }
383 }
384
385
386 static inline uint64_t
387 hpet_get_reg (struct hpet_state * hpet, addr_t guest_addr) 
388 {
389     /* we don't care about the lower 3 bits at this point */
390     guest_addr &= ~7;
391
392     switch (guest_addr) {
393         case GEN_CAP_REG_OFFSET: 
394             return hpet->regs.caps.value;
395         case GEN_CFG_REG_OFFSET:
396             return hpet->regs.cfg.value;
397         case GEN_ISR_OFFSET:
398             return hpet->regs.irq_status.value;
399         case MAIN_CNTR_VAL_REG_OFFSET:
400             return read_hpet_counter(hpet);
401         case TIMER_N_OFFSET_CFG(0): 
402         case TIMER_N_OFFSET_CFG(1): 
403         case TIMER_N_OFFSET_CFG(2): 
404             return hpet->regs.timers[TIMER_N(CFG, guest_addr)].caps.value;
405         case TIMER_N_OFFSET_CMP(0):
406         case TIMER_N_OFFSET_CMP(1):
407         case TIMER_N_OFFSET_CMP(2):
408              return read_hpet_comparator(hpet, TIMER_N(CMP, guest_addr));
409         case TIMER_N_OFFSET_FSB_IRR(0):
410         case TIMER_N_OFFSET_FSB_IRR(1):
411         case TIMER_N_OFFSET_FSB_IRR(2):
412              return hpet->regs.timers[TIMER_N(FSB_IRR, guest_addr)].fsb_int_route.value;
413     }
414
415     return 0;
416 }
417
418
419 static int 
420 hpet_read (struct guest_info * core, addr_t guest_addr, void * dst, uint_t length, void * priv_data) 
421 {
422     struct hpet_state * hpet = (struct hpet_state *)priv_data;
423     uint_t flags = 0;
424     uint64_t reg;
425     unsigned long res;
426
427     /* we only care about the lower 9 bits */
428     guest_addr &= HPET_REGION_SIZE - 1;
429
430     if (check_hpet_access(core, guest_addr, length) != 0) {
431         res = ~0UL;
432         goto out;
433     }
434
435     flags = v3_lock_irqsave(hpet->lock);
436
437     reg = hpet_get_reg(hpet, guest_addr);
438
439     res = reg;
440
441     /* shift and mask out high-order bits if this is smaller than a 64-bit read */
442     if (length != 8) {
443         res = (reg >> ((guest_addr & 7) * 8)) & ((1ULL << (length * 8)) - 1);
444     }
445
446     v3_unlock_irqrestore(hpet->lock, flags);
447 out:
448     PrintDebug(core->vm_info, core, "HPET: core %u: at %p: Read HPET address space (%p), length=%u, val=0x%lx\n",
449                core->vcpu_id, hpet, (void *)guest_addr, length, res);
450     *(unsigned long*)dst = res;
451     return 0;
452 }
453
454
455 /* timer functions */
456
457 static void 
458 hpet_update_time (struct guest_info * core, 
459                               uint64_t cpu_cycles, uint64_t cpu_freq, 
460                               void * priv_data) 
461 {
462     struct hpet_timer_state * htimer = (struct hpet_timer_state *)(priv_data);
463     struct hpet_state * hpet = htimer->hpet;
464     unsigned int nr = htimer->timer_num;
465     uint64_t hpet_ticks = read_hpet_counter(hpet);
466
467     /* KCH TODO: handle missed timer interrupts?? */
468     if (hpet_ticks >= hpet->comparator[nr]) {
469         v3_raise_irq(core->vm_info, htimer->timer_num);
470
471         /* we do this to update the comparator value,
472          * e.g. in case we missed an interrupt */
473         read_hpet_comparator(hpet, nr);
474     } 
475 }
476
477
478 static struct v3_timer_ops timer_ops = {
479     .update_timer = hpet_update_time,
480 };
481
482
483 static void 
484 hpet_stop_timer (struct hpet_state * hpet, unsigned int n)
485 {
486
487     V3_ASSERT(hpet->core->vm_info, hpet->core, n < HPET_NUM_TIMERS);
488     if (hpet->timer_states[n].timer) {
489         v3_remove_timer(hpet->core, hpet->timer_states[n].timer);
490         hpet->timer_states[n].timer = NULL;
491     }
492     // synch the comparator for reads that may happen while we're stopped
493     read_hpet_comparator(hpet, n);
494 }
495
496
497 static void 
498 hpet_start_timer (struct hpet_state * hpet, unsigned int n) 
499 {
500     uint64_t timer_comp, tick;
501
502     V3_ASSERT(hpet->core->vm_info, hpet->core, n < HPET_NUM_TIMERS);
503     if (n == 0 && hpet->regs.cfg.leg_rt_cnf) {
504         /* KCH TODO: the PIT shouldn't be generating irqs on chan 0 if this bit is set 
505          * AFAIK we don't have an interface to do this just yet
506          */
507     }
508
509     if (!is_timer_enabled(hpet, n)) {
510         return;
511     }
512
513     timer_comp = read_hpet_comparator(hpet, n);
514     tick = read_hpet_counter(hpet);
515
516     if (timer_32bit(hpet, n)) {
517         timer_comp = (uint32_t)read_hpet_comparator(hpet, n);
518         tick = (uint32_t)read_hpet_counter(hpet);
519     }
520         
521     /* if LegacyReplacementRoute is set, 
522      * "Timer 0 will be routed to IRQ0 in Non-APIC or IRQ2 in the I/O APIC
523      *  Timer 1 will be routed to IRQ8 in Non-APIC or IRQ8 in the I/O APIC
524      *  Timer 2-n will be routed as per the routing in the timer n config registers"
525      * see IA-PC HPET Spec pp.12-13
526      */
527     if ((n <= 1) && (hpet->regs.cfg.leg_rt_cnf)) {
528         hpet->timer_states[n].irq = (n == 0) ? 0 : 8;
529     } else {
530         hpet->timer_states[n].irq = hpet->regs.timers[n].caps.tn_int_route_cnf;
531     }
532
533     hpet->timer_states[n].oneshot = !in_periodic_mode(hpet, n);
534     hpet->timer_states[n].timer   = v3_add_timer(hpet->core, &timer_ops, &hpet->timer_states[n]);
535
536     if (hpet->timer_states[n].timer == NULL) {
537         PrintError(hpet->core->vm_info, hpet->core, "HPET: Failed to attach HPET timer %d to core %d\n", n, hpet->core->vcpu_id);
538         return;
539     }
540 }
541
542
543 /* this ensures that only allowed bits in a given register are 
544  * changed */
545 static inline uint64_t 
546 hpet_mask_write (uint64_t new, uint64_t old, uint64_t mask) 
547 {
548     new &= mask;
549     new |= old & ~mask;
550     return new;
551 }
552
553
554 static int 
555 hpet_write (struct guest_info * core, addr_t guest_addr, void * src, uint_t length, void * priv_data) 
556 {
557     struct hpet_state * hpet = (struct hpet_state *)(priv_data);
558     uint_t flags = 0;
559     uint64_t old, new;
560     unsigned long to_start = 0;
561     unsigned long to_stop  = 0;
562     int timer_n, i;
563
564 #define mark_timer_to_start(n)     (set_timer_bit(to_start, n))
565 #define mark_timer_to_stop(n)      (set_timer_bit(to_stop, n))
566 #define mark_timer_to_reset(n)     (mark_timer_to_stop(n), mark_timer_to_start(n))
567
568     guest_addr &= HPET_REGION_SIZE - 1;
569
570     PrintDebug(core->vm_info, core, "HPET: core %u: write to address space (%p) (val=%x)\n", 
571                core->vcpu_id, (void *)guest_addr, *(uint32_t *)src);
572
573     if (check_hpet_access(core, guest_addr, length) != 0) {
574         goto out_prelock;
575     }
576
577     flags = v3_lock_irqsave(hpet->lock);
578
579     old = hpet_get_reg(hpet, guest_addr);
580     new = *(unsigned long *)src;
581
582     /* this is a trick to convert a non-8byte write into one,
583      * making sure that we only change the bits of the word
584      * within the length of the write */
585     if (length != 8) {
586         // say it's a 2-byte write to offset 6
587         new = hpet_mask_write(new << (guest_addr & 7) * 8,  // left shift the value by 48
588                               old,
589                              ((1ULL << (length*8)) - 1) << ((guest_addr & 7) * 8)); // then mask out all but the last 2 bytes
590     }
591
592     switch (guest_addr & ~7) {
593
594         case GEN_CFG_REG_OFFSET:
595             hpet->regs.cfg.value = hpet_mask_write(new, old, 0x3);
596  
597             /* we're starting the timer */
598             if ( !(old & HPET_CFG_ENABLE) && (new & HPET_CFG_ENABLE) ) {
599
600                 hpet->counter_offset = hpet->regs.main_counter - hpet_guest_time(hpet);
601                 //hpet->counter_offset = hpet_guest_time(hpet) - hpet->regs.main_counter;
602                 PrintDebug(core->vm_info, core, "HPET: starting the hpet, setting offset to 0x%llx\n", hpet->counter_offset);
603
604                 for (i = 0; i < HPET_NUM_TIMERS; i++) {
605                     hpet->comparator[i] = timer_32bit(hpet, i) ?
606                                             (uint32_t)hpet->regs.timers[i].comp.value :
607                                                       hpet->regs.timers[i].comp.value;
608                     if (is_timer_enabled(hpet, i)) {
609                         mark_timer_to_start(i);
610                     }
611                 }
612
613             /* we're stopping the timer */
614             } else if ( (old & HPET_CFG_ENABLE) && !(new & HPET_CFG_ENABLE) ) {
615                 PrintDebug(core->vm_info, core, "HPET: stopping the hpet\n");
616
617                 hpet->regs.main_counter = hpet->counter_offset + hpet_guest_time(hpet);
618
619                 for (i = 0; i < HPET_NUM_TIMERS; i++) {
620                     if (is_timer_enabled(hpet, i)) {
621                         mark_timer_to_stop(i);
622                     }
623                 }
624
625             }
626             break;
627
628         case MAIN_CNTR_VAL_REG_OFFSET:
629             hpet->regs.main_counter = new;
630             PrintDebug(core->vm_info, core, "HPET: writing the main counter (0x%llx)\n", new);
631             if (is_hpet_enabled(hpet)) {
632                 PrintError(core->vm_info, core, "HPET: writing main counter in unhalted state\n");
633                 for (i = 0; i < HPET_NUM_TIMERS; i++) {
634                     if (is_timer_enabled(hpet, i)) {
635                         mark_timer_to_reset(i);
636                     }
637                 }
638             }
639
640             break;
641         case TIMER_N_OFFSET_CFG(0): 
642         case TIMER_N_OFFSET_CFG(1): 
643         case TIMER_N_OFFSET_CFG(2): 
644             /* KCH: software should set the main counter to 0 before setting a comparator */
645             timer_n = TIMER_N(CFG, guest_addr);
646             hpet->regs.timers[timer_n].caps.value = hpet_mask_write(new, old, 0x3F4E);
647
648             if (is_timer_ltrig(hpet, timer_n)) {
649                 PrintError(core->vm_info, core, "HPET: level-triggered interrupts not supported\n");
650                 goto out_err;
651             }
652
653             /* are we switching the timer to 32-bit mode? */
654             if (new & HPET_TIMER_32BIT) {
655                 hpet->regs.timers[timer_n].comp.value = (uint32_t) hpet->regs.timers[timer_n].comp.value;
656                 hpet->period[timer_n] = (uint32_t)hpet->period[timer_n];
657             }
658
659             if (is_hpet_enabled(hpet)) {
660
661                 if (new & HPET_TIMER_ENABLE) {
662                         /* we're switching to or from periodic mode, reset */
663                         if ((new ^ old) & HPET_TIMER_PERIODIC) {
664                             PrintDebug(core->vm_info, core, "HPET: changing periodic mode on timer %d\n", timer_n);
665                             mark_timer_to_reset(timer_n);
666                         /* we're switching from 64 to 32, reset */
667                         } else if ((new & HPET_TIMER_32BIT) && !(old & HPET_TIMER_32BIT)) {
668                             PrintDebug(core->vm_info, core, "HPET: changing timer %d from 32-bit to 64-bit mode\n", timer_n);
669                             mark_timer_to_reset(timer_n);
670                         } else if (!(old & HPET_TIMER_ENABLE)) {
671                             PrintDebug(core->vm_info, core, "HPET: activating timer %d\n", timer_n);
672                             mark_timer_to_start(timer_n);
673                         }
674
675                 } else if (old & HPET_TIMER_ENABLE) {
676                     PrintDebug(core->vm_info, core, "HPET: deactivating timer %d\n", timer_n);
677                     mark_timer_to_stop(timer_n);
678                 }
679             }
680
681             break;
682         case TIMER_N_OFFSET_CMP(0):
683         case TIMER_N_OFFSET_CMP(1):
684         case TIMER_N_OFFSET_CMP(2):
685             timer_n = TIMER_N(CMP, guest_addr);
686
687             if (timer_32bit(hpet, timer_n)) {
688                 new = (uint32_t)new;
689             }
690             
691             PrintDebug(core->vm_info, core, "HPET: writing comparator reg on timer %d (val=0x%llx)\n", timer_n, new);
692
693             hpet->regs.timers[timer_n].comp.value = new;
694             
695             /* this bit means sw can set the comp directly
696              * The bit gets cleared on a write to the comp
697              */
698             if (hpet->regs.timers[timer_n].caps.tn_val_set_cnf) {
699                 hpet->regs.timers[timer_n].caps.tn_val_set_cnf = 0;
700             } else if (in_periodic_mode(hpet, timer_n)) {
701                     
702                 /* set bounds on the period */
703                 if (tick_to_ns(hpet, new) < 100000) {
704                     new = (100000 << 10) / hpet->ns_per_tick;
705                 }
706
707                 new &= ((timer_32bit(hpet, timer_n)) ? ~0UL : ~0ULL) >> 1;
708                 hpet->period[timer_n] = new;
709                 PrintDebug(core->vm_info, core, "HPET: period for timer %d to (0x%llx)\n", timer_n, hpet->period[timer_n]);
710             }
711
712             hpet->comparator[timer_n] = new;
713
714             if (is_hpet_enabled(hpet) && is_timer_enabled(hpet, timer_n)) {
715                 mark_timer_to_reset(timer_n);
716             }
717             
718             break;
719         case TIMER_N_OFFSET_FSB_IRR(0):
720         case TIMER_N_OFFSET_FSB_IRR(1):
721         case TIMER_N_OFFSET_FSB_IRR(2):
722             timer_n = TIMER_N(FSB_IRR, guest_addr);
723             PrintDebug(core->vm_info, core, "HPET: writing to fsb_irr reg for timer %d (val=0x%llx\n", timer_n, new);
724             hpet->regs.timers[timer_n].fsb_int_route.value = new;
725             break;
726
727         default:
728             /* just ignore writes to unsupported regs */
729            break;
730     }
731
732     /* now we update the timers that we marked */
733     while (to_stop)
734     {
735         i = first_bit(to_stop);
736         unset_timer_bit(to_stop, i);
737         hpet_stop_timer(hpet, i);
738     }
739
740     while (to_start)
741     {
742         i = first_bit(to_start);
743         unset_timer_bit(to_start, i);
744         hpet_start_timer(hpet, i);
745     }
746
747 #undef mark_timer_to_start
748 #undef mark_timer_to_stop
749 #undef mark_timer_to_reset
750
751     v3_unlock_irqrestore(hpet->lock, flags);
752 out_prelock:
753     return 0;
754 out_err:
755     v3_unlock_irqrestore(hpet->lock, flags);
756     return -1;
757 }
758
759
760 static int 
761 hpet_free (struct hpet_state * hpet) 
762 {
763     struct v3_vm_info * vm   = NULL;
764         struct guest_info * core = NULL;
765
766     if (!hpet) {
767         return -1;
768     }
769
770     core = hpet->core;
771         vm   = core->vm_info;
772     
773     remove_hpet_timers(hpet);
774
775     v3_lock_deinit(&(hpet->lock));
776
777     if (v3_unhook_mem(vm, core->vcpu_id, hpet->base_addr)) {
778         PrintError(vm, VCORE_NONE, "HPET: could not unhook memory region\n");
779     }
780
781     V3_Free(hpet);
782     return 0;
783 }
784
785
786 #ifdef V3_CONFIG_CHECKPOINT
787
788 static int 
789 hpet_save (struct v3_chkpt_ctx * ctx, void * private_data) 
790 {
791     PrintError(VM_NONE, VCORE_NONE, "Unimplemented\n");
792     return -1;
793 }
794
795
796 static int 
797 hpet_load (struct v3_chkpt_ctx * ctx, void * private_data) 
798 {
799     PrintError(VM_NONE, VCORE_NONE, "Unimplemented\n");
800     return -1;
801 }
802
803 #endif
804
805 static struct v3_device_ops dev_ops = {
806     .free = (int (*)(void *))hpet_free,
807 #ifdef V3_CONFIG_CHECKPOINT
808     .save = hpet_save,
809     .load = hpet_load
810 #endif
811 };
812
813
814 static int 
815 hpet_init (struct v3_vm_info * vm, v3_cfg_tree_t * cfg) 
816 {
817     char * dev_id = v3_cfg_val(cfg, "ID");
818     struct hpet_state * hpet;
819     struct guest_info * core = NULL;
820     struct vm_device * dev = NULL;
821     int i;
822
823     core = &vm->cores[0];
824
825     PrintDebug(vm, VCORE_NONE, "HPET: Creating HPET\n");
826
827     hpet = (struct hpet_state *)V3_Malloc(sizeof(struct hpet_state));
828
829     if (!hpet) {
830         PrintError(vm, VCORE_NONE, "HPET: Failed to allocate space for HPET\n");
831         return -1;
832     }
833
834     hpet->core = core;
835
836     dev = v3_add_device(vm, dev_id, &dev_ops, hpet);
837
838     if (dev == NULL) {
839         PrintError(vm, VCORE_NONE, "HPET: Could not attach device %s\n", dev_id);
840         goto out_err;
841     }
842
843     hpet->system_freq = core->time_state.host_cpu_freq * 1000; // convert from kHz
844     hpet->ns_per_tick = ((NANOSECS * HPET_PERIOD) << 10) / hpet->system_freq;
845     hpet->max_ns_res  = ~0ULL / hpet->ns_per_tick;
846
847     PrintDebug(core->vm_info, core, "HPET: System frequency detected as %lluHz\n", hpet->system_freq);
848
849     v3_lock_init(&(hpet->lock)); 
850
851     PrintDebug(core->vm_info, core, "HPET: Initializing %d timers\n", HPET_NUM_TIMERS);
852
853     for (i = 0; i < HPET_NUM_TIMERS; i++) {
854         hpet->timer_states[i].timer_num = i;
855         hpet->timer_states[i].hpet      = hpet;
856         hpet->timer_states[i].timer     = NULL;
857     }
858
859     /* init architecturally visible state */
860         init_hpet_state(hpet);
861
862     PrintDebug(core->vm_info, core "HPET: Hooking HPET mem region at %p\n", (void*)hpet->base_addr);
863         if (v3_hook_full_mem(vm, 
864                          V3_MEM_CORE_ANY, 
865                          hpet->base_addr, 
866                          hpet->base_addr + HPET_REGION_SIZE, 
867                          hpet_read, 
868                          hpet_write, 
869                          hpet) < 0) {
870         PrintError(vm, VCORE_NONE, "HPET: Failed to map HPET memory region\n");
871         goto out_err1;
872     }
873
874     PrintDebug(vm, VCORE_NONE, "HPET: Initialization complete\n");
875
876     return 0;
877
878 out_err1: 
879     v3_lock_deinit(&(hpet->lock));
880     v3_remove_device(dev);
881 out_err:
882     V3_Free(hpet);
883     return -1;
884 }
885
886 device_register("HPET", hpet_init)