xref: /qemu/hw/timer/hpet.c (revision 6ff5da16000f908140723e164d33a0b51a6c4162)
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 "exec/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 
92 static uint32_t hpet_in_legacy_mode(HPETState *s)
93 {
94     return s->config & HPET_CFG_LEGACY;
95 }
96 
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 
102 static uint32_t timer_fsb_route(HPETTimer *t)
103 {
104     return t->config & HPET_TN_FSB_ENABLE;
105 }
106 
107 static uint32_t hpet_enabled(HPETState *s)
108 {
109     return s->config & HPET_CFG_ENABLE;
110 }
111 
112 static uint32_t timer_is_periodic(HPETTimer *t)
113 {
114     return t->config & HPET_TN_PERIODIC;
115 }
116 
117 static uint32_t timer_enabled(HPETTimer *t)
118 {
119     return t->config & HPET_TN_ENABLE;
120 }
121 
122 static uint32_t hpet_time_after(uint64_t a, uint64_t b)
123 {
124     return ((int64_t)(b - a) < 0);
125 }
126 
127 static uint64_t ticks_to_ns(uint64_t value)
128 {
129     return value * HPET_CLK_PERIOD;
130 }
131 
132 static uint64_t ns_to_ticks(uint64_t value)
133 {
134     return value / HPET_CLK_PERIOD;
135 }
136 
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 
144 static int activating_bit(uint64_t old, uint64_t new, uint64_t mask)
145 {
146     return (!(old & mask) && (new & mask));
147 }
148 
149 static int deactivating_bit(uint64_t old, uint64_t new, uint64_t mask)
150 {
151     return ((old & mask) && !(new & mask));
152 }
153 
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 
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  */
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 
182 static uint64_t hpet_next_wrap(uint64_t cur_tick)
183 {
184     return (cur_tick | 0xffffffffU) + 1;
185 }
186 
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 
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 
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 
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 
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 
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 = 1,
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_V(num_timers_save, HPETState, 2),
339         VMSTATE_VALIDATE("num_timers must match", hpet_validate_num_timers),
340         VMSTATE_STRUCT_VARRAY_UINT8(timer, HPETState, num_timers, 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 
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  */
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 
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 
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 
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 
430     /*address range of all TN regs*/
431     if (addr >= 0x100 && addr <= 0x3ff) {
432         uint8_t timer_id = (addr - 0x100) / 0x20;
433         HPETTimer *timer = &s->timer[timer_id];
434 
435         if (timer_id > s->num_timers) {
436             trace_hpet_timer_id_out_of_range(timer_id);
437             return 0;
438         }
439 
440         switch (addr & 0x18) {
441         case HPET_TN_CFG: // including interrupt capabilities
442             return timer->config >> shift;
443         case HPET_TN_CMP: // comparator register
444             return timer->cmp >> shift;
445         case HPET_TN_ROUTE:
446             return timer->fsb >> shift;
447         default:
448             trace_hpet_ram_read_invalid();
449             break;
450         }
451     } else {
452         switch (addr & ~4) {
453         case HPET_ID: // including HPET_PERIOD
454             return s->capability >> shift;
455         case HPET_CFG:
456             return s->config >> shift;
457         case HPET_COUNTER:
458             if (hpet_enabled(s)) {
459                 cur_tick = hpet_get_ticks(s);
460             } else {
461                 cur_tick = s->hpet_counter;
462             }
463             trace_hpet_ram_read_reading_counter(addr & 4, cur_tick);
464             return cur_tick >> shift;
465         case HPET_STATUS:
466             return s->isr >> shift;
467         default:
468             trace_hpet_ram_read_invalid();
469             break;
470         }
471     }
472     return 0;
473 }
474 
475 static void hpet_ram_write(void *opaque, hwaddr addr,
476                            uint64_t value, unsigned size)
477 {
478     int i;
479     HPETState *s = opaque;
480     int shift = (addr & 4) * 8;
481     int len = MIN(size * 8, 64 - shift);
482     uint64_t old_val, new_val, cleared;
483 
484     trace_hpet_ram_write(addr, value);
485 
486     /*address range of all TN regs*/
487     if (addr >= 0x100 && addr <= 0x3ff) {
488         uint8_t timer_id = (addr - 0x100) / 0x20;
489         HPETTimer *timer = &s->timer[timer_id];
490 
491         trace_hpet_ram_write_timer_id(timer_id);
492         if (timer_id > s->num_timers) {
493             trace_hpet_timer_id_out_of_range(timer_id);
494             return;
495         }
496         switch (addr & 0x18) {
497         case HPET_TN_CFG:
498             trace_hpet_ram_write_tn_cfg(addr & 4);
499             old_val = timer->config;
500             new_val = deposit64(old_val, shift, len, value);
501             new_val = hpet_fixup_reg(new_val, old_val, HPET_TN_CFG_WRITE_MASK);
502             if (deactivating_bit(old_val, new_val, HPET_TN_TYPE_LEVEL)) {
503                 /*
504                  * Do this before changing timer->config; otherwise, if
505                  * HPET_TN_FSB is set, update_irq will not lower the qemu_irq.
506                  */
507                 update_irq(timer, 0);
508             }
509             timer->config = new_val;
510             if (activating_bit(old_val, new_val, HPET_TN_ENABLE)
511                 && (s->isr & (1 << timer_id))) {
512                 update_irq(timer, 1);
513             }
514             if (new_val & HPET_TN_32BIT) {
515                 timer->cmp = (uint32_t)timer->cmp;
516                 timer->period = (uint32_t)timer->period;
517             }
518             if (hpet_enabled(s)) {
519                 hpet_set_timer(timer);
520             }
521             break;
522         case HPET_TN_CMP: // comparator register
523             if (timer->config & HPET_TN_32BIT) {
524                 /* High 32-bits are zero, leave them untouched.  */
525                 if (shift) {
526                     trace_hpet_ram_write_invalid_tn_cmp();
527                     break;
528                 }
529                 len = 64;
530                 value = (uint32_t) value;
531             }
532             trace_hpet_ram_write_tn_cmp(addr & 4);
533             if (!timer_is_periodic(timer)
534                 || (timer->config & HPET_TN_SETVAL)) {
535                 timer->cmp = deposit64(timer->cmp, shift, len, value);
536             }
537             if (timer_is_periodic(timer)) {
538                 timer->period = deposit64(timer->period, shift, len, value);
539             }
540             timer->config &= ~HPET_TN_SETVAL;
541             if (hpet_enabled(s)) {
542                 hpet_set_timer(timer);
543             }
544             break;
545         case HPET_TN_ROUTE:
546             timer->fsb = deposit64(timer->fsb, shift, len, value);
547             break;
548         default:
549             trace_hpet_ram_write_invalid();
550             break;
551         }
552         return;
553     } else {
554         switch (addr & ~4) {
555         case HPET_ID:
556             return;
557         case HPET_CFG:
558             old_val = s->config;
559             new_val = deposit64(old_val, shift, len, value);
560             new_val = hpet_fixup_reg(new_val, old_val, HPET_CFG_WRITE_MASK);
561             s->config = new_val;
562             if (activating_bit(old_val, new_val, HPET_CFG_ENABLE)) {
563                 /* Enable main counter and interrupt generation. */
564                 s->hpet_offset =
565                     ticks_to_ns(s->hpet_counter) - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
566                 for (i = 0; i < s->num_timers; i++) {
567                     if (timer_enabled(&s->timer[i]) && (s->isr & (1 << i))) {
568                         update_irq(&s->timer[i], 1);
569                     }
570                     hpet_set_timer(&s->timer[i]);
571                 }
572             } else if (deactivating_bit(old_val, new_val, HPET_CFG_ENABLE)) {
573                 /* Halt main counter and disable interrupt generation. */
574                 s->hpet_counter = hpet_get_ticks(s);
575                 for (i = 0; i < s->num_timers; i++) {
576                     hpet_del_timer(&s->timer[i]);
577                 }
578             }
579             /* i8254 and RTC output pins are disabled
580              * when HPET is in legacy mode */
581             if (activating_bit(old_val, new_val, HPET_CFG_LEGACY)) {
582                 qemu_set_irq(s->pit_enabled, 0);
583                 qemu_irq_lower(s->irqs[0]);
584                 qemu_irq_lower(s->irqs[RTC_ISA_IRQ]);
585             } else if (deactivating_bit(old_val, new_val, HPET_CFG_LEGACY)) {
586                 qemu_irq_lower(s->irqs[0]);
587                 qemu_set_irq(s->pit_enabled, 1);
588                 qemu_set_irq(s->irqs[RTC_ISA_IRQ], s->rtc_irq_level);
589             }
590             break;
591         case HPET_STATUS:
592             new_val = value << shift;
593             cleared = new_val & s->isr;
594             for (i = 0; i < s->num_timers; i++) {
595                 if (cleared & (1 << i)) {
596                     update_irq(&s->timer[i], 0);
597                 }
598             }
599             break;
600         case HPET_COUNTER:
601             if (hpet_enabled(s)) {
602                 trace_hpet_ram_write_counter_write_while_enabled();
603             }
604             s->hpet_counter = deposit64(s->hpet_counter, shift, len, value);
605             break;
606         default:
607             trace_hpet_ram_write_invalid();
608             break;
609         }
610     }
611 }
612 
613 static const MemoryRegionOps hpet_ram_ops = {
614     .read = hpet_ram_read,
615     .write = hpet_ram_write,
616     .valid = {
617         .min_access_size = 4,
618         .max_access_size = 8,
619     },
620     .impl = {
621         .min_access_size = 4,
622         .max_access_size = 8,
623     },
624     .endianness = DEVICE_NATIVE_ENDIAN,
625 };
626 
627 static void hpet_reset(DeviceState *d)
628 {
629     HPETState *s = HPET(d);
630     SysBusDevice *sbd = SYS_BUS_DEVICE(d);
631     int i;
632 
633     for (i = 0; i < s->num_timers; i++) {
634         HPETTimer *timer = &s->timer[i];
635 
636         hpet_del_timer(timer);
637         timer->cmp = ~0ULL;
638         timer->config = HPET_TN_PERIODIC_CAP | HPET_TN_SIZE_CAP;
639         if (s->flags & (1 << HPET_MSI_SUPPORT)) {
640             timer->config |= HPET_TN_FSB_CAP;
641         }
642         /* advertise availability of ioapic int */
643         timer->config |=  (uint64_t)s->intcap << 32;
644         timer->period = 0ULL;
645         timer->wrap_flag = 0;
646     }
647 
648     qemu_set_irq(s->pit_enabled, 1);
649     s->hpet_counter = 0ULL;
650     s->hpet_offset = 0ULL;
651     s->config = 0ULL;
652     hpet_fw_cfg.hpet[s->hpet_id].event_timer_block_id = (uint32_t)s->capability;
653     hpet_fw_cfg.hpet[s->hpet_id].address = sbd->mmio[0].addr;
654 
655     /* to document that the RTC lowers its output on reset as well */
656     s->rtc_irq_level = 0;
657 }
658 
659 static void hpet_handle_legacy_irq(void *opaque, int n, int level)
660 {
661     HPETState *s = HPET(opaque);
662 
663     if (n == HPET_LEGACY_PIT_INT) {
664         if (!hpet_in_legacy_mode(s)) {
665             qemu_set_irq(s->irqs[0], level);
666         }
667     } else {
668         s->rtc_irq_level = level;
669         if (!hpet_in_legacy_mode(s)) {
670             qemu_set_irq(s->irqs[RTC_ISA_IRQ], level);
671         }
672     }
673 }
674 
675 static void hpet_init(Object *obj)
676 {
677     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
678     HPETState *s = HPET(obj);
679 
680     /* HPET Area */
681     memory_region_init_io(&s->iomem, obj, &hpet_ram_ops, s, "hpet", HPET_LEN);
682     sysbus_init_mmio(sbd, &s->iomem);
683 }
684 
685 static void hpet_realize(DeviceState *dev, Error **errp)
686 {
687     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
688     HPETState *s = HPET(dev);
689     int i;
690     HPETTimer *timer;
691 
692     if (!s->intcap) {
693         warn_report("Hpet's intcap not initialized");
694     }
695     if (hpet_fw_cfg.count == UINT8_MAX) {
696         /* first instance */
697         hpet_fw_cfg.count = 0;
698     }
699 
700     if (hpet_fw_cfg.count == 8) {
701         error_setg(errp, "Only 8 instances of HPET is allowed");
702         return;
703     }
704 
705     s->hpet_id = hpet_fw_cfg.count++;
706 
707     for (i = 0; i < HPET_NUM_IRQ_ROUTES; i++) {
708         sysbus_init_irq(sbd, &s->irqs[i]);
709     }
710 
711     if (s->num_timers < HPET_MIN_TIMERS) {
712         s->num_timers = HPET_MIN_TIMERS;
713     } else if (s->num_timers > HPET_MAX_TIMERS) {
714         s->num_timers = HPET_MAX_TIMERS;
715     }
716     for (i = 0; i < HPET_MAX_TIMERS; i++) {
717         timer = &s->timer[i];
718         timer->qemu_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, hpet_timer, timer);
719         timer->tn = i;
720         timer->state = s;
721     }
722 
723     /* 64-bit General Capabilities and ID Register; LegacyReplacementRoute. */
724     s->capability = 0x8086a001ULL;
725     s->capability |= (s->num_timers - 1) << HPET_ID_NUM_TIM_SHIFT;
726     s->capability |= ((uint64_t)(HPET_CLK_PERIOD * FS_PER_NS) << 32);
727 
728     qdev_init_gpio_in(dev, hpet_handle_legacy_irq, 2);
729     qdev_init_gpio_out(dev, &s->pit_enabled, 1);
730 }
731 
732 static const Property hpet_device_properties[] = {
733     DEFINE_PROP_UINT8("timers", HPETState, num_timers, HPET_MIN_TIMERS),
734     DEFINE_PROP_BIT("msi", HPETState, flags, HPET_MSI_SUPPORT, false),
735     DEFINE_PROP_UINT32(HPET_INTCAP, HPETState, intcap, 0),
736     DEFINE_PROP_BOOL("hpet-offset-saved", HPETState, hpet_offset_saved, true),
737 };
738 
739 static void hpet_device_class_init(ObjectClass *klass, void *data)
740 {
741     DeviceClass *dc = DEVICE_CLASS(klass);
742 
743     dc->realize = hpet_realize;
744     device_class_set_legacy_reset(dc, hpet_reset);
745     dc->vmsd = &vmstate_hpet;
746     device_class_set_props(dc, hpet_device_properties);
747 }
748 
749 static const TypeInfo hpet_device_info = {
750     .name          = TYPE_HPET,
751     .parent        = TYPE_SYS_BUS_DEVICE,
752     .instance_size = sizeof(HPETState),
753     .instance_init = hpet_init,
754     .class_init    = hpet_device_class_init,
755 };
756 
757 static void hpet_register_types(void)
758 {
759     type_register_static(&hpet_device_info);
760 }
761 
762 type_init(hpet_register_types)
763