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
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 = 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
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
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
hpet_ram_write(void * opaque,hwaddr addr,uint64_t value,unsigned size)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
hpet_reset(DeviceState * d)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
hpet_handle_legacy_irq(void * opaque,int n,int level)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
hpet_init(Object * obj)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
hpet_realize(DeviceState * dev,Error ** errp)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
hpet_device_class_init(ObjectClass * klass,void * data)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
hpet_register_types(void)757 static void hpet_register_types(void)
758 {
759 type_register_static(&hpet_device_info);
760 }
761
762 type_init(hpet_register_types)
763