xref: /qemu/hw/timer/hpet.c (revision 96215036f47403438c7c7869b7cd419bd7a11f82)
1 /*
2  *  High Precision Event Timer emulation
3  *
4  *  Copyright (c) 2007 Alexander Graf
5  *  Copyright (c) 2008 IBM Corporation
6  *
7  *  Authors: Beth Kon <bkon@us.ibm.com>
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
21  *
22  * *****************************************************************
23  *
24  * This driver attempts to emulate an HPET device in software.
25  */
26 
27 #include "qemu/osdep.h"
28 #include "hw/irq.h"
29 #include "qapi/error.h"
30 #include "qemu/error-report.h"
31 #include "qemu/timer.h"
32 #include "hw/qdev-properties.h"
33 #include "hw/timer/hpet.h"
34 #include "hw/sysbus.h"
35 #include "hw/rtc/mc146818rtc.h"
36 #include "hw/rtc/mc146818rtc_regs.h"
37 #include "migration/vmstate.h"
38 #include "hw/timer/i8254.h"
39 #include "system/address-spaces.h"
40 #include "qom/object.h"
41 #include "trace.h"
42 
43 struct hpet_fw_config hpet_fw_cfg = {.count = UINT8_MAX};
44 
45 #define HPET_MSI_SUPPORT        0
46 
47 OBJECT_DECLARE_SIMPLE_TYPE(HPETState, HPET)
48 
49 struct HPETState;
50 typedef struct HPETTimer {  /* timers */
51     uint8_t tn;             /*timer number*/
52     QEMUTimer *qemu_timer;
53     struct HPETState *state;
54     /* Memory-mapped, software visible timer registers */
55     uint64_t config;        /* configuration/cap */
56     uint64_t cmp;           /* comparator */
57     uint64_t fsb;           /* FSB route */
58     /* Hidden register state */
59     uint64_t cmp64;         /* comparator (extended to counter width) */
60     uint64_t period;        /* Last value written to comparator */
61     uint8_t wrap_flag;      /* timer pop will indicate wrap for one-shot 32-bit
62                              * mode. Next pop will be actual timer expiration.
63                              */
64     uint64_t last;          /* last value armed, to avoid timer storms */
65 } HPETTimer;
66 
67 struct HPETState {
68     /*< private >*/
69     SysBusDevice parent_obj;
70     /*< public >*/
71 
72     MemoryRegion iomem;
73     uint64_t hpet_offset;
74     bool hpet_offset_saved;
75     qemu_irq irqs[HPET_NUM_IRQ_ROUTES];
76     uint32_t flags;
77     uint8_t rtc_irq_level;
78     qemu_irq pit_enabled;
79     uint8_t num_timers;
80     uint8_t num_timers_save;
81     uint32_t intcap;
82     HPETTimer timer[HPET_MAX_TIMERS];
83 
84     /* Memory-mapped, software visible registers */
85     uint64_t capability;        /* capabilities */
86     uint64_t config;            /* configuration */
87     uint64_t isr;               /* interrupt status reg */
88     uint64_t hpet_counter;      /* main counter */
89     uint8_t  hpet_id;           /* instance id */
90 };
91 
hpet_in_legacy_mode(HPETState * s)92 static uint32_t hpet_in_legacy_mode(HPETState *s)
93 {
94     return s->config & HPET_CFG_LEGACY;
95 }
96 
timer_int_route(struct HPETTimer * timer)97 static uint32_t timer_int_route(struct HPETTimer *timer)
98 {
99     return (timer->config & HPET_TN_INT_ROUTE_MASK) >> HPET_TN_INT_ROUTE_SHIFT;
100 }
101 
timer_fsb_route(HPETTimer * t)102 static uint32_t timer_fsb_route(HPETTimer *t)
103 {
104     return t->config & HPET_TN_FSB_ENABLE;
105 }
106 
hpet_enabled(HPETState * s)107 static uint32_t hpet_enabled(HPETState *s)
108 {
109     return s->config & HPET_CFG_ENABLE;
110 }
111 
timer_is_periodic(HPETTimer * t)112 static uint32_t timer_is_periodic(HPETTimer *t)
113 {
114     return t->config & HPET_TN_PERIODIC;
115 }
116 
timer_enabled(HPETTimer * t)117 static uint32_t timer_enabled(HPETTimer *t)
118 {
119     return t->config & HPET_TN_ENABLE;
120 }
121 
hpet_time_after(uint64_t a,uint64_t b)122 static uint32_t hpet_time_after(uint64_t a, uint64_t b)
123 {
124     return ((int64_t)(b - a) < 0);
125 }
126 
ticks_to_ns(uint64_t value)127 static uint64_t ticks_to_ns(uint64_t value)
128 {
129     return value * HPET_CLK_PERIOD;
130 }
131 
ns_to_ticks(uint64_t value)132 static uint64_t ns_to_ticks(uint64_t value)
133 {
134     return value / HPET_CLK_PERIOD;
135 }
136 
hpet_fixup_reg(uint64_t new,uint64_t old,uint64_t mask)137 static uint64_t hpet_fixup_reg(uint64_t new, uint64_t old, uint64_t mask)
138 {
139     new &= mask;
140     new |= old & ~mask;
141     return new;
142 }
143 
activating_bit(uint64_t old,uint64_t new,uint64_t mask)144 static int activating_bit(uint64_t old, uint64_t new, uint64_t mask)
145 {
146     return (!(old & mask) && (new & mask));
147 }
148 
deactivating_bit(uint64_t old,uint64_t new,uint64_t mask)149 static int deactivating_bit(uint64_t old, uint64_t new, uint64_t mask)
150 {
151     return ((old & mask) && !(new & mask));
152 }
153 
hpet_get_ticks(HPETState * s)154 static uint64_t hpet_get_ticks(HPETState *s)
155 {
156     return ns_to_ticks(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->hpet_offset);
157 }
158 
hpet_get_ns(HPETState * s,uint64_t tick)159 static uint64_t hpet_get_ns(HPETState *s, uint64_t tick)
160 {
161     return ticks_to_ns(tick) - s->hpet_offset;
162 }
163 
164 /*
165  * calculate next value of the general counter that matches the
166  * target (either entirely, or the low 32-bit only depending on
167  * the timer mode).
168  */
hpet_calculate_cmp64(HPETTimer * t,uint64_t cur_tick,uint64_t target)169 static uint64_t hpet_calculate_cmp64(HPETTimer *t, uint64_t cur_tick, uint64_t target)
170 {
171     if (t->config & HPET_TN_32BIT) {
172         uint64_t result = deposit64(cur_tick, 0, 32, target);
173         if (result < cur_tick) {
174             result += 0x100000000ULL;
175         }
176         return result;
177     } else {
178         return target;
179     }
180 }
181 
hpet_next_wrap(uint64_t cur_tick)182 static uint64_t hpet_next_wrap(uint64_t cur_tick)
183 {
184     return (cur_tick | 0xffffffffU) + 1;
185 }
186 
update_irq(struct HPETTimer * timer,int set)187 static void update_irq(struct HPETTimer *timer, int set)
188 {
189     uint64_t mask;
190     HPETState *s;
191     int route;
192 
193     if (timer->tn <= 1 && hpet_in_legacy_mode(timer->state)) {
194         /* if LegacyReplacementRoute bit is set, HPET specification requires
195          * timer0 be routed to IRQ0 in NON-APIC or IRQ2 in the I/O APIC,
196          * timer1 be routed to IRQ8 in NON-APIC or IRQ8 in the I/O APIC.
197          */
198         route = (timer->tn == 0) ? 0 : RTC_ISA_IRQ;
199     } else {
200         route = timer_int_route(timer);
201     }
202     s = timer->state;
203     mask = 1 << timer->tn;
204 
205     if (set && (timer->config & HPET_TN_TYPE_LEVEL)) {
206         /*
207          * If HPET_TN_ENABLE bit is 0, "the timer will still operate and
208          * generate appropriate status bits, but will not cause an interrupt"
209          */
210         s->isr |= mask;
211     } else {
212         s->isr &= ~mask;
213     }
214 
215     if (set && timer_enabled(timer) && hpet_enabled(s)) {
216         if (timer_fsb_route(timer)) {
217             address_space_stl_le(&address_space_memory, timer->fsb >> 32,
218                                  timer->fsb & 0xffffffff, MEMTXATTRS_UNSPECIFIED,
219                                  NULL);
220         } else if (timer->config & HPET_TN_TYPE_LEVEL) {
221             qemu_irq_raise(s->irqs[route]);
222         } else {
223             qemu_irq_pulse(s->irqs[route]);
224         }
225     } else {
226         if (!timer_fsb_route(timer)) {
227             qemu_irq_lower(s->irqs[route]);
228         }
229     }
230 }
231 
hpet_pre_save(void * opaque)232 static int hpet_pre_save(void *opaque)
233 {
234     HPETState *s = opaque;
235 
236     /* save current counter value */
237     if (hpet_enabled(s)) {
238         s->hpet_counter = hpet_get_ticks(s);
239     }
240 
241     /*
242      * The number of timers must match on source and destination, but it was
243      * also added to the migration stream.  Check that it matches the value
244      * that was configured.
245      */
246     s->num_timers_save = s->num_timers;
247     return 0;
248 }
249 
hpet_validate_num_timers(void * opaque,int version_id)250 static bool hpet_validate_num_timers(void *opaque, int version_id)
251 {
252     HPETState *s = opaque;
253 
254     return s->num_timers == s->num_timers_save;
255 }
256 
hpet_post_load(void * opaque,int version_id)257 static int hpet_post_load(void *opaque, int version_id)
258 {
259     HPETState *s = opaque;
260     int i;
261 
262     for (i = 0; i < s->num_timers; i++) {
263         HPETTimer *t = &s->timer[i];
264         t->cmp64 = hpet_calculate_cmp64(t, s->hpet_counter, t->cmp);
265         t->last = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - NANOSECONDS_PER_SECOND;
266     }
267     /* Recalculate the offset between the main counter and guest time */
268     if (!s->hpet_offset_saved) {
269         s->hpet_offset = ticks_to_ns(s->hpet_counter)
270                         - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
271     }
272 
273     return 0;
274 }
275 
hpet_offset_needed(void * opaque)276 static bool hpet_offset_needed(void *opaque)
277 {
278     HPETState *s = opaque;
279 
280     return hpet_enabled(s) && s->hpet_offset_saved;
281 }
282 
hpet_rtc_irq_level_needed(void * opaque)283 static bool hpet_rtc_irq_level_needed(void *opaque)
284 {
285     HPETState *s = opaque;
286 
287     return s->rtc_irq_level != 0;
288 }
289 
290 static const VMStateDescription vmstate_hpet_rtc_irq_level = {
291     .name = "hpet/rtc_irq_level",
292     .version_id = 1,
293     .minimum_version_id = 1,
294     .needed = hpet_rtc_irq_level_needed,
295     .fields = (const VMStateField[]) {
296         VMSTATE_UINT8(rtc_irq_level, HPETState),
297         VMSTATE_END_OF_LIST()
298     }
299 };
300 
301 static const VMStateDescription vmstate_hpet_offset = {
302     .name = "hpet/offset",
303     .version_id = 1,
304     .minimum_version_id = 1,
305     .needed = hpet_offset_needed,
306     .fields = (const VMStateField[]) {
307         VMSTATE_UINT64(hpet_offset, HPETState),
308         VMSTATE_END_OF_LIST()
309     }
310 };
311 
312 static const VMStateDescription vmstate_hpet_timer = {
313     .name = "hpet_timer",
314     .version_id = 1,
315     .minimum_version_id = 1,
316     .fields = (const VMStateField[]) {
317         VMSTATE_UINT8(tn, HPETTimer),
318         VMSTATE_UINT64(config, HPETTimer),
319         VMSTATE_UINT64(cmp, HPETTimer),
320         VMSTATE_UINT64(fsb, HPETTimer),
321         VMSTATE_UINT64(period, HPETTimer),
322         VMSTATE_UINT8(wrap_flag, HPETTimer),
323         VMSTATE_TIMER_PTR(qemu_timer, HPETTimer),
324         VMSTATE_END_OF_LIST()
325     }
326 };
327 
328 static const VMStateDescription vmstate_hpet = {
329     .name = "hpet",
330     .version_id = 2,
331     .minimum_version_id = 2,
332     .pre_save = hpet_pre_save,
333     .post_load = hpet_post_load,
334     .fields = (const VMStateField[]) {
335         VMSTATE_UINT64(config, HPETState),
336         VMSTATE_UINT64(isr, HPETState),
337         VMSTATE_UINT64(hpet_counter, HPETState),
338         VMSTATE_UINT8(num_timers_save, HPETState),
339         VMSTATE_VALIDATE("num_timers must match", hpet_validate_num_timers),
340         VMSTATE_STRUCT_VARRAY_UINT8(timer, HPETState, num_timers_save, 0,
341                                     vmstate_hpet_timer, HPETTimer),
342         VMSTATE_END_OF_LIST()
343     },
344     .subsections = (const VMStateDescription * const []) {
345         &vmstate_hpet_rtc_irq_level,
346         &vmstate_hpet_offset,
347         NULL
348     }
349 };
350 
hpet_arm(HPETTimer * t,uint64_t tick)351 static void hpet_arm(HPETTimer *t, uint64_t tick)
352 {
353     uint64_t ns = hpet_get_ns(t->state, tick);
354 
355     /* Clamp period to reasonable min value (1 us) */
356     if (timer_is_periodic(t) && ns - t->last < 1000) {
357         ns = t->last + 1000;
358     }
359 
360     t->last = ns;
361     timer_mod(t->qemu_timer, ns);
362 }
363 
364 /*
365  * timer expiration callback
366  */
hpet_timer(void * opaque)367 static void hpet_timer(void *opaque)
368 {
369     HPETTimer *t = opaque;
370     uint64_t period = t->period;
371     uint64_t cur_tick = hpet_get_ticks(t->state);
372 
373     if (timer_is_periodic(t) && period != 0) {
374         while (hpet_time_after(cur_tick, t->cmp64)) {
375             t->cmp64 += period;
376         }
377         if (t->config & HPET_TN_32BIT) {
378             t->cmp = (uint32_t)t->cmp64;
379         } else {
380             t->cmp = t->cmp64;
381         }
382         hpet_arm(t, t->cmp64);
383     } else if (t->wrap_flag) {
384         t->wrap_flag = 0;
385         hpet_arm(t, t->cmp64);
386     }
387     update_irq(t, 1);
388 }
389 
hpet_set_timer(HPETTimer * t)390 static void hpet_set_timer(HPETTimer *t)
391 {
392     uint64_t cur_tick = hpet_get_ticks(t->state);
393 
394     t->wrap_flag = 0;
395     t->cmp64 = hpet_calculate_cmp64(t, cur_tick, t->cmp);
396     if (t->config & HPET_TN_32BIT) {
397 
398         /* hpet spec says in one-shot 32-bit mode, generate an interrupt when
399          * counter wraps in addition to an interrupt with comparator match.
400          */
401         if (!timer_is_periodic(t) && t->cmp64 > hpet_next_wrap(cur_tick)) {
402             t->wrap_flag = 1;
403             hpet_arm(t, hpet_next_wrap(cur_tick));
404             return;
405         }
406     }
407     hpet_arm(t, t->cmp64);
408 }
409 
hpet_del_timer(HPETTimer * t)410 static void hpet_del_timer(HPETTimer *t)
411 {
412     HPETState *s = t->state;
413     timer_del(t->qemu_timer);
414 
415     if (s->isr & (1 << t->tn)) {
416         /* For level-triggered interrupt, this leaves ISR set but lowers irq.  */
417         update_irq(t, 1);
418     }
419 }
420 
hpet_ram_read(void * opaque,hwaddr addr,unsigned size)421 static uint64_t hpet_ram_read(void *opaque, hwaddr addr,
422                               unsigned size)
423 {
424     HPETState *s = opaque;
425     int shift = (addr & 4) * 8;
426     uint64_t cur_tick;
427 
428     trace_hpet_ram_read(addr);
429     addr &= ~4;
430 
431     /*address range of all global regs*/
432     if (addr <= 0xff) {
433         switch (addr) {
434         case HPET_ID: // including HPET_PERIOD
435             return s->capability >> shift;
436         case HPET_CFG:
437             return s->config >> shift;
438         case HPET_COUNTER:
439             if (hpet_enabled(s)) {
440                 cur_tick = hpet_get_ticks(s);
441             } else {
442                 cur_tick = s->hpet_counter;
443             }
444             trace_hpet_ram_read_reading_counter(addr & 4, cur_tick);
445             return cur_tick >> shift;
446         case HPET_STATUS:
447             return s->isr >> shift;
448         default:
449             trace_hpet_ram_read_invalid();
450             break;
451         }
452     } else {
453         uint8_t timer_id = (addr - 0x100) / 0x20;
454         HPETTimer *timer = &s->timer[timer_id];
455 
456         if (timer_id > s->num_timers) {
457             trace_hpet_timer_id_out_of_range(timer_id);
458             return 0;
459         }
460 
461         switch (addr & 0x1f) {
462         case HPET_TN_CFG: // including interrupt capabilities
463             return timer->config >> shift;
464         case HPET_TN_CMP: // comparator register
465             return timer->cmp >> shift;
466         case HPET_TN_ROUTE:
467             return timer->fsb >> shift;
468         default:
469             trace_hpet_ram_read_invalid();
470             break;
471         }
472     }
473     return 0;
474 }
475 
hpet_ram_write(void * opaque,hwaddr addr,uint64_t value,unsigned size)476 static void hpet_ram_write(void *opaque, hwaddr addr,
477                            uint64_t value, unsigned size)
478 {
479     int i;
480     HPETState *s = opaque;
481     int shift = (addr & 4) * 8;
482     int len = MIN(size * 8, 64 - shift);
483     uint64_t old_val, new_val, cleared;
484 
485     trace_hpet_ram_write(addr, value);
486     addr &= ~4;
487 
488     /*address range of all global regs*/
489     if (addr <= 0xff) {
490         switch (addr) {
491         case HPET_ID:
492             return;
493         case HPET_CFG:
494             old_val = s->config;
495             new_val = deposit64(old_val, shift, len, value);
496             new_val = hpet_fixup_reg(new_val, old_val, HPET_CFG_WRITE_MASK);
497             s->config = new_val;
498             if (activating_bit(old_val, new_val, HPET_CFG_ENABLE)) {
499                 /* Enable main counter and interrupt generation. */
500                 s->hpet_offset =
501                     ticks_to_ns(s->hpet_counter) - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
502                 for (i = 0; i < s->num_timers; i++) {
503                     if (timer_enabled(&s->timer[i]) && (s->isr & (1 << i))) {
504                         update_irq(&s->timer[i], 1);
505                     }
506                     hpet_set_timer(&s->timer[i]);
507                 }
508             } else if (deactivating_bit(old_val, new_val, HPET_CFG_ENABLE)) {
509                 /* Halt main counter and disable interrupt generation. */
510                 s->hpet_counter = hpet_get_ticks(s);
511                 for (i = 0; i < s->num_timers; i++) {
512                     hpet_del_timer(&s->timer[i]);
513                 }
514             }
515             /* i8254 and RTC output pins are disabled
516              * when HPET is in legacy mode */
517             if (activating_bit(old_val, new_val, HPET_CFG_LEGACY)) {
518                 qemu_set_irq(s->pit_enabled, 0);
519                 qemu_irq_lower(s->irqs[0]);
520                 qemu_irq_lower(s->irqs[RTC_ISA_IRQ]);
521             } else if (deactivating_bit(old_val, new_val, HPET_CFG_LEGACY)) {
522                 qemu_irq_lower(s->irqs[0]);
523                 qemu_set_irq(s->pit_enabled, 1);
524                 qemu_set_irq(s->irqs[RTC_ISA_IRQ], s->rtc_irq_level);
525             }
526             break;
527         case HPET_STATUS:
528             new_val = value << shift;
529             cleared = new_val & s->isr;
530             for (i = 0; i < s->num_timers; i++) {
531                 if (cleared & (1 << i)) {
532                     update_irq(&s->timer[i], 0);
533                 }
534             }
535             break;
536         case HPET_COUNTER:
537             if (hpet_enabled(s)) {
538                 trace_hpet_ram_write_counter_write_while_enabled();
539             }
540             s->hpet_counter = deposit64(s->hpet_counter, shift, len, value);
541             break;
542         default:
543             trace_hpet_ram_write_invalid();
544             break;
545         }
546     } else {
547         uint8_t timer_id = (addr - 0x100) / 0x20;
548         HPETTimer *timer = &s->timer[timer_id];
549 
550         trace_hpet_ram_write_timer_id(timer_id);
551         if (timer_id > s->num_timers) {
552             trace_hpet_timer_id_out_of_range(timer_id);
553             return;
554         }
555         switch (addr & 0x18) {
556         case HPET_TN_CFG:
557             trace_hpet_ram_write_tn_cfg(addr & 4);
558             old_val = timer->config;
559             new_val = deposit64(old_val, shift, len, value);
560             new_val = hpet_fixup_reg(new_val, old_val, HPET_TN_CFG_WRITE_MASK);
561             if (deactivating_bit(old_val, new_val, HPET_TN_TYPE_LEVEL)) {
562                 /*
563                  * Do this before changing timer->config; otherwise, if
564                  * HPET_TN_FSB is set, update_irq will not lower the qemu_irq.
565                  */
566                 update_irq(timer, 0);
567             }
568             timer->config = new_val;
569             if (activating_bit(old_val, new_val, HPET_TN_ENABLE)
570                 && (s->isr & (1 << timer_id))) {
571                 update_irq(timer, 1);
572             }
573             if (new_val & HPET_TN_32BIT) {
574                 timer->cmp = (uint32_t)timer->cmp;
575                 timer->period = (uint32_t)timer->period;
576             }
577             if (hpet_enabled(s)) {
578                 hpet_set_timer(timer);
579             }
580             break;
581         case HPET_TN_CMP: // comparator register
582             if (timer->config & HPET_TN_32BIT) {
583                 /* High 32-bits are zero, leave them untouched.  */
584                 if (shift) {
585                     trace_hpet_ram_write_invalid_tn_cmp();
586                     break;
587                 }
588                 len = 64;
589                 value = (uint32_t) value;
590             }
591             trace_hpet_ram_write_tn_cmp(addr & 4);
592             if (!timer_is_periodic(timer)
593                 || (timer->config & HPET_TN_SETVAL)) {
594                 timer->cmp = deposit64(timer->cmp, shift, len, value);
595             }
596             if (timer_is_periodic(timer)) {
597                 timer->period = deposit64(timer->period, shift, len, value);
598             }
599             timer->config &= ~HPET_TN_SETVAL;
600             if (hpet_enabled(s)) {
601                 hpet_set_timer(timer);
602             }
603             break;
604         case HPET_TN_ROUTE:
605             timer->fsb = deposit64(timer->fsb, shift, len, value);
606             break;
607         default:
608             trace_hpet_ram_write_invalid();
609             break;
610         }
611         return;
612     }
613 }
614 
615 static const MemoryRegionOps hpet_ram_ops = {
616     .read = hpet_ram_read,
617     .write = hpet_ram_write,
618     .valid = {
619         .min_access_size = 4,
620         .max_access_size = 8,
621     },
622     .impl = {
623         .min_access_size = 4,
624         .max_access_size = 8,
625     },
626     .endianness = DEVICE_NATIVE_ENDIAN,
627 };
628 
hpet_reset(DeviceState * d)629 static void hpet_reset(DeviceState *d)
630 {
631     HPETState *s = HPET(d);
632     SysBusDevice *sbd = SYS_BUS_DEVICE(d);
633     int i;
634 
635     for (i = 0; i < s->num_timers; i++) {
636         HPETTimer *timer = &s->timer[i];
637 
638         hpet_del_timer(timer);
639         timer->cmp = ~0ULL;
640         timer->config = HPET_TN_PERIODIC_CAP | HPET_TN_SIZE_CAP;
641         if (s->flags & (1 << HPET_MSI_SUPPORT)) {
642             timer->config |= HPET_TN_FSB_CAP;
643         }
644         /* advertise availability of ioapic int */
645         timer->config |=  (uint64_t)s->intcap << 32;
646         timer->period = 0ULL;
647         timer->wrap_flag = 0;
648     }
649 
650     qemu_set_irq(s->pit_enabled, 1);
651     s->hpet_counter = 0ULL;
652     s->hpet_offset = 0ULL;
653     s->config = 0ULL;
654     hpet_fw_cfg.hpet[s->hpet_id].event_timer_block_id = (uint32_t)s->capability;
655     hpet_fw_cfg.hpet[s->hpet_id].address = sbd->mmio[0].addr;
656 
657     /* to document that the RTC lowers its output on reset as well */
658     s->rtc_irq_level = 0;
659 }
660 
hpet_handle_legacy_irq(void * opaque,int n,int level)661 static void hpet_handle_legacy_irq(void *opaque, int n, int level)
662 {
663     HPETState *s = HPET(opaque);
664 
665     if (n == HPET_LEGACY_PIT_INT) {
666         if (!hpet_in_legacy_mode(s)) {
667             qemu_set_irq(s->irqs[0], level);
668         }
669     } else {
670         s->rtc_irq_level = level;
671         if (!hpet_in_legacy_mode(s)) {
672             qemu_set_irq(s->irqs[RTC_ISA_IRQ], level);
673         }
674     }
675 }
676 
hpet_init(Object * obj)677 static void hpet_init(Object *obj)
678 {
679     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
680     HPETState *s = HPET(obj);
681 
682     /* HPET Area */
683     memory_region_init_io(&s->iomem, obj, &hpet_ram_ops, s, "hpet", HPET_LEN);
684     sysbus_init_mmio(sbd, &s->iomem);
685 }
686 
hpet_realize(DeviceState * dev,Error ** errp)687 static void hpet_realize(DeviceState *dev, Error **errp)
688 {
689     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
690     HPETState *s = HPET(dev);
691     int i;
692     HPETTimer *timer;
693 
694     if (s->num_timers < HPET_MIN_TIMERS || s->num_timers > HPET_MAX_TIMERS) {
695         error_setg(errp, "hpet.num_timers must be between %d and %d",
696                    HPET_MIN_TIMERS, HPET_MAX_TIMERS);
697         return;
698     }
699     if (!s->intcap) {
700         error_setg(errp, "hpet.hpet-intcap not initialized");
701         return;
702     }
703     if (hpet_fw_cfg.count == UINT8_MAX) {
704         /* first instance */
705         hpet_fw_cfg.count = 0;
706     }
707 
708     if (hpet_fw_cfg.count == 8) {
709         error_setg(errp, "Only 8 instances of HPET are allowed");
710         return;
711     }
712 
713     s->hpet_id = hpet_fw_cfg.count++;
714 
715     for (i = 0; i < HPET_NUM_IRQ_ROUTES; i++) {
716         sysbus_init_irq(sbd, &s->irqs[i]);
717     }
718 
719     for (i = 0; i < HPET_MAX_TIMERS; i++) {
720         timer = &s->timer[i];
721         timer->qemu_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, hpet_timer, timer);
722         timer->tn = i;
723         timer->state = s;
724     }
725 
726     /* 64-bit General Capabilities and ID Register; LegacyReplacementRoute. */
727     s->capability = 0x8086a001ULL;
728     s->capability |= (s->num_timers - 1) << HPET_ID_NUM_TIM_SHIFT;
729     s->capability |= ((uint64_t)(HPET_CLK_PERIOD * FS_PER_NS) << 32);
730 
731     qdev_init_gpio_in(dev, hpet_handle_legacy_irq, 2);
732     qdev_init_gpio_out(dev, &s->pit_enabled, 1);
733 }
734 
735 static const Property hpet_device_properties[] = {
736     DEFINE_PROP_UINT8("timers", HPETState, num_timers, HPET_MIN_TIMERS),
737     DEFINE_PROP_BIT("msi", HPETState, flags, HPET_MSI_SUPPORT, false),
738     DEFINE_PROP_UINT32(HPET_INTCAP, HPETState, intcap, 0),
739     DEFINE_PROP_BOOL("hpet-offset-saved", HPETState, hpet_offset_saved, true),
740 };
741 
hpet_device_class_init(ObjectClass * klass,const void * data)742 static void hpet_device_class_init(ObjectClass *klass, const void *data)
743 {
744     DeviceClass *dc = DEVICE_CLASS(klass);
745 
746     dc->realize = hpet_realize;
747     device_class_set_legacy_reset(dc, hpet_reset);
748     dc->vmsd = &vmstate_hpet;
749     device_class_set_props(dc, hpet_device_properties);
750 }
751 
752 static const TypeInfo hpet_device_info = {
753     .name          = TYPE_HPET,
754     .parent        = TYPE_SYS_BUS_DEVICE,
755     .instance_size = sizeof(HPETState),
756     .instance_init = hpet_init,
757     .class_init    = hpet_device_class_init,
758 };
759 
hpet_register_types(void)760 static void hpet_register_types(void)
761 {
762     type_register_static(&hpet_device_info);
763 }
764 
765 type_init(hpet_register_types)
766