xref: /qemu/rust/hw/timer/hpet/src/device.rs (revision 7bda68e8e2b0b836639557ddb13d761bdd15a104)
1 // Copyright (C) 2024 Intel Corporation.
2 // Author(s): Zhao Liu <zhai1.liu@intel.com>
3 // SPDX-License-Identifier: GPL-2.0-or-later
4 
5 use std::{
6     ffi::CStr,
7     pin::Pin,
8     ptr::{addr_of_mut, null_mut, NonNull},
9     slice::from_ref,
10 };
11 
12 use qemu_api::{
13     bindings::{
14         address_space_memory, address_space_stl_le, qdev_prop_bit, qdev_prop_bool,
15         qdev_prop_uint32, qdev_prop_usize,
16     },
17     c_str,
18     cell::{BqlCell, BqlRefCell},
19     irq::InterruptSource,
20     memory::{
21         hwaddr, MemoryRegion, MemoryRegionOps, MemoryRegionOpsBuilder, MEMTXATTRS_UNSPECIFIED,
22     },
23     prelude::*,
24     qdev::{DeviceImpl, DeviceMethods, DeviceState, Property, ResetType, ResettablePhasesImpl},
25     qom::{ObjectImpl, ObjectType, ParentField},
26     qom_isa,
27     sysbus::{SysBusDevice, SysBusDeviceImpl},
28     timer::{Timer, CLOCK_VIRTUAL},
29 };
30 
31 use crate::fw_cfg::HPETFwConfig;
32 
33 /// Register space for each timer block (`HPET_BASE` is defined in hpet.h).
34 const HPET_REG_SPACE_LEN: u64 = 0x400; // 1024 bytes
35 
36 /// Minimum recommended hardware implementation.
37 const HPET_MIN_TIMERS: usize = 3;
38 /// Maximum timers in each timer block.
39 const HPET_MAX_TIMERS: usize = 32;
40 
41 /// Flags that HPETState.flags supports.
42 const HPET_FLAG_MSI_SUPPORT_SHIFT: usize = 0;
43 
44 const HPET_NUM_IRQ_ROUTES: usize = 32;
45 const HPET_LEGACY_PIT_INT: u32 = 0; // HPET_LEGACY_RTC_INT isn't defined here.
46 const RTC_ISA_IRQ: usize = 8;
47 
48 const HPET_CLK_PERIOD: u64 = 10; // 10 ns
49 const FS_PER_NS: u64 = 1000000; // 1000000 femtoseconds == 1 ns
50 
51 /// Revision ID (bits 0:7). Revision 1 is implemented (refer to v1.0a spec).
52 const HPET_CAP_REV_ID_VALUE: u64 = 0x1;
53 const HPET_CAP_REV_ID_SHIFT: usize = 0;
54 /// Number of Timers (bits 8:12)
55 const HPET_CAP_NUM_TIM_SHIFT: usize = 8;
56 /// Counter Size (bit 13)
57 const HPET_CAP_COUNT_SIZE_CAP_SHIFT: usize = 13;
58 /// Legacy Replacement Route Capable (bit 15)
59 const HPET_CAP_LEG_RT_CAP_SHIFT: usize = 15;
60 /// Vendor ID (bits 16:31)
61 const HPET_CAP_VENDER_ID_VALUE: u64 = 0x8086;
62 const HPET_CAP_VENDER_ID_SHIFT: usize = 16;
63 /// Main Counter Tick Period (bits 32:63)
64 const HPET_CAP_CNT_CLK_PERIOD_SHIFT: usize = 32;
65 
66 /// Overall Enable (bit 0)
67 const HPET_CFG_ENABLE_SHIFT: usize = 0;
68 /// Legacy Replacement Route (bit 1)
69 const HPET_CFG_LEG_RT_SHIFT: usize = 1;
70 /// Other bits are reserved.
71 const HPET_CFG_WRITE_MASK: u64 = 0x003;
72 
73 /// bit 0, 7, and bits 16:31 are reserved.
74 /// bit 4, 5, 15, and bits 32:64 are read-only.
75 const HPET_TN_CFG_WRITE_MASK: u64 = 0x7f4e;
76 /// Timer N Interrupt Type (bit 1)
77 const HPET_TN_CFG_INT_TYPE_SHIFT: usize = 1;
78 /// Timer N Interrupt Enable (bit 2)
79 const HPET_TN_CFG_INT_ENABLE_SHIFT: usize = 2;
80 /// Timer N Type (Periodic enabled or not, bit 3)
81 const HPET_TN_CFG_PERIODIC_SHIFT: usize = 3;
82 /// Timer N Periodic Interrupt Capable (support Periodic or not, bit 4)
83 const HPET_TN_CFG_PERIODIC_CAP_SHIFT: usize = 4;
84 /// Timer N Size (timer size is 64-bits or 32 bits, bit 5)
85 const HPET_TN_CFG_SIZE_CAP_SHIFT: usize = 5;
86 /// Timer N Value Set (bit 6)
87 const HPET_TN_CFG_SETVAL_SHIFT: usize = 6;
88 /// Timer N 32-bit Mode (bit 8)
89 const HPET_TN_CFG_32BIT_SHIFT: usize = 8;
90 /// Timer N Interrupt Rout (bits 9:13)
91 const HPET_TN_CFG_INT_ROUTE_MASK: u64 = 0x3e00;
92 const HPET_TN_CFG_INT_ROUTE_SHIFT: usize = 9;
93 /// Timer N FSB Interrupt Enable (bit 14)
94 const HPET_TN_CFG_FSB_ENABLE_SHIFT: usize = 14;
95 /// Timer N FSB Interrupt Delivery (bit 15)
96 const HPET_TN_CFG_FSB_CAP_SHIFT: usize = 15;
97 /// Timer N Interrupt Routing Capability (bits 32:63)
98 const HPET_TN_CFG_INT_ROUTE_CAP_SHIFT: usize = 32;
99 
100 #[derive(qemu_api_macros::TryInto)]
101 #[repr(u64)]
102 #[allow(non_camel_case_types)]
103 /// Timer registers, masked by 0x18
104 enum TimerRegister {
105     /// Timer N Configuration and Capability Register
106     CFG = 0,
107     /// Timer N Comparator Value Register
108     CMP = 8,
109     /// Timer N FSB Interrupt Route Register
110     ROUTE = 16,
111 }
112 
113 #[derive(qemu_api_macros::TryInto)]
114 #[repr(u64)]
115 #[allow(non_camel_case_types)]
116 /// Global registers
117 enum GlobalRegister {
118     /// General Capabilities and ID Register
119     CAP = 0,
120     /// General Configuration Register
121     CFG = 0x10,
122     /// General Interrupt Status Register
123     INT_STATUS = 0x20,
124     /// Main Counter Value Register
125     COUNTER = 0xF0,
126 }
127 
128 enum HPETRegister<'a> {
129     /// Global register in the range from `0` to `0xff`
130     Global(GlobalRegister),
131 
132     /// Register in the timer block `0x100`...`0x3ff`
133     Timer(&'a BqlRefCell<HPETTimer>, TimerRegister),
134 
135     /// Invalid address
136     #[allow(dead_code)]
137     Unknown(hwaddr),
138 }
139 
140 struct HPETAddrDecode<'a> {
141     shift: u32,
142     len: u32,
143     reg: HPETRegister<'a>,
144 }
145 
146 const fn hpet_next_wrap(cur_tick: u64) -> u64 {
147     (cur_tick | 0xffffffff) + 1
148 }
149 
150 const fn hpet_time_after(a: u64, b: u64) -> bool {
151     ((b - a) as i64) < 0
152 }
153 
154 const fn ticks_to_ns(value: u64) -> u64 {
155     value * HPET_CLK_PERIOD
156 }
157 
158 const fn ns_to_ticks(value: u64) -> u64 {
159     value / HPET_CLK_PERIOD
160 }
161 
162 // Avoid touching the bits that cannot be written.
163 const fn hpet_fixup_reg(new: u64, old: u64, mask: u64) -> u64 {
164     (new & mask) | (old & !mask)
165 }
166 
167 const fn activating_bit(old: u64, new: u64, shift: usize) -> bool {
168     let mask: u64 = 1 << shift;
169     (old & mask == 0) && (new & mask != 0)
170 }
171 
172 const fn deactivating_bit(old: u64, new: u64, shift: usize) -> bool {
173     let mask: u64 = 1 << shift;
174     (old & mask != 0) && (new & mask == 0)
175 }
176 
177 fn timer_handler(timer_cell: &BqlRefCell<HPETTimer>) {
178     timer_cell.borrow_mut().callback()
179 }
180 
181 /// HPET Timer Abstraction
182 #[repr(C)]
183 #[derive(Debug, qemu_api_macros::offsets)]
184 pub struct HPETTimer {
185     /// timer N index within the timer block (`HPETState`)
186     #[doc(alias = "tn")]
187     index: usize,
188     qemu_timer: Timer,
189     /// timer block abstraction containing this timer
190     state: NonNull<HPETState>,
191 
192     // Memory-mapped, software visible timer registers
193     /// Timer N Configuration and Capability Register
194     config: u64,
195     /// Timer N Comparator Value Register
196     cmp: u64,
197     /// Timer N FSB Interrupt Route Register
198     fsb: u64,
199 
200     // Hidden register state
201     /// comparator (extended to counter width)
202     cmp64: u64,
203     /// Last value written to comparator
204     period: u64,
205     /// timer pop will indicate wrap for one-shot 32-bit
206     /// mode. Next pop will be actual timer expiration.
207     wrap_flag: u8,
208     /// last value armed, to avoid timer storms
209     last: u64,
210 }
211 
212 impl HPETTimer {
213     fn init(&mut self, index: usize, state: &HPETState) {
214         *self = HPETTimer {
215             index,
216             // SAFETY: the HPETTimer will only be used after the timer
217             // is initialized below.
218             qemu_timer: unsafe { Timer::new() },
219             state: NonNull::new(state as *const _ as *mut _).unwrap(),
220             config: 0,
221             cmp: 0,
222             fsb: 0,
223             cmp64: 0,
224             period: 0,
225             wrap_flag: 0,
226             last: 0,
227         };
228 
229         // SAFETY: HPETTimer is only used as part of HPETState, which is
230         // always pinned.
231         let qemu_timer = unsafe { Pin::new_unchecked(&mut self.qemu_timer) };
232         qemu_timer.init_full(
233             None,
234             CLOCK_VIRTUAL,
235             Timer::NS,
236             0,
237             timer_handler,
238             &state.timers[self.index],
239         )
240     }
241 
242     fn get_state(&self) -> &HPETState {
243         // SAFETY:
244         // the pointer is convertible to a reference
245         unsafe { self.state.as_ref() }
246     }
247 
248     fn is_int_active(&self) -> bool {
249         self.get_state().is_timer_int_active(self.index)
250     }
251 
252     const fn is_fsb_route_enabled(&self) -> bool {
253         self.config & (1 << HPET_TN_CFG_FSB_ENABLE_SHIFT) != 0
254     }
255 
256     const fn is_periodic(&self) -> bool {
257         self.config & (1 << HPET_TN_CFG_PERIODIC_SHIFT) != 0
258     }
259 
260     const fn is_int_enabled(&self) -> bool {
261         self.config & (1 << HPET_TN_CFG_INT_ENABLE_SHIFT) != 0
262     }
263 
264     const fn is_32bit_mod(&self) -> bool {
265         self.config & (1 << HPET_TN_CFG_32BIT_SHIFT) != 0
266     }
267 
268     const fn is_valset_enabled(&self) -> bool {
269         self.config & (1 << HPET_TN_CFG_SETVAL_SHIFT) != 0
270     }
271 
272     fn clear_valset(&mut self) {
273         self.config &= !(1 << HPET_TN_CFG_SETVAL_SHIFT);
274     }
275 
276     /// True if timer interrupt is level triggered; otherwise, edge triggered.
277     const fn is_int_level_triggered(&self) -> bool {
278         self.config & (1 << HPET_TN_CFG_INT_TYPE_SHIFT) != 0
279     }
280 
281     /// calculate next value of the general counter that matches the
282     /// target (either entirely, or the low 32-bit only depending on
283     /// the timer mode).
284     fn calculate_cmp64(&self, cur_tick: u64, target: u64) -> u64 {
285         if self.is_32bit_mod() {
286             let mut result: u64 = cur_tick.deposit(0, 32, target);
287             if result < cur_tick {
288                 result += 0x100000000;
289             }
290             result
291         } else {
292             target
293         }
294     }
295 
296     const fn get_individual_route(&self) -> usize {
297         ((self.config & HPET_TN_CFG_INT_ROUTE_MASK) >> HPET_TN_CFG_INT_ROUTE_SHIFT) as usize
298     }
299 
300     fn get_int_route(&self) -> usize {
301         if self.index <= 1 && self.get_state().is_legacy_mode() {
302             // If LegacyReplacement Route bit is set, HPET specification requires
303             // timer0 be routed to IRQ0 in NON-APIC or IRQ2 in the I/O APIC,
304             // timer1 be routed to IRQ8 in NON-APIC or IRQ8 in the I/O APIC.
305             //
306             // If the LegacyReplacement Route bit is set, the individual routing
307             // bits for timers 0 and 1 (APIC or FSB) will have no impact.
308             //
309             // FIXME: Consider I/O APIC case.
310             if self.index == 0 {
311                 0
312             } else {
313                 RTC_ISA_IRQ
314             }
315         } else {
316             // (If the LegacyReplacement Route bit is set) Timer 2-n will be
317             // routed as per the routing in the timer n config registers.
318             // ...
319             // If the LegacyReplacement Route bit is not set, the individual
320             // routing bits for each of the timers are used.
321             self.get_individual_route()
322         }
323     }
324 
325     fn set_irq(&mut self, set: bool) {
326         let route = self.get_int_route();
327 
328         if set && self.is_int_enabled() && self.get_state().is_hpet_enabled() {
329             if self.is_fsb_route_enabled() {
330                 // SAFETY:
331                 // the parameters are valid.
332                 unsafe {
333                     address_space_stl_le(
334                         addr_of_mut!(address_space_memory),
335                         self.fsb >> 32,  // Timer N FSB int addr
336                         self.fsb as u32, // Timer N FSB int value, truncate!
337                         MEMTXATTRS_UNSPECIFIED,
338                         null_mut(),
339                     );
340                 }
341             } else if self.is_int_level_triggered() {
342                 self.get_state().irqs[route].raise();
343             } else {
344                 self.get_state().irqs[route].pulse();
345             }
346         } else if !self.is_fsb_route_enabled() {
347             self.get_state().irqs[route].lower();
348         }
349     }
350 
351     fn update_irq(&mut self, set: bool) {
352         // If Timer N Interrupt Enable bit is 0, "the timer will
353         // still operate and generate appropriate status bits, but
354         // will not cause an interrupt"
355         self.get_state()
356             .update_int_status(self.index as u32, set && self.is_int_level_triggered());
357         self.set_irq(set);
358     }
359 
360     fn arm_timer(&mut self, tick: u64) {
361         let mut ns = self.get_state().get_ns(tick);
362 
363         // Clamp period to reasonable min value (1 us)
364         if self.is_periodic() && ns - self.last < 1000 {
365             ns = self.last + 1000;
366         }
367 
368         self.last = ns;
369         self.qemu_timer.modify(self.last);
370     }
371 
372     fn set_timer(&mut self) {
373         let cur_tick: u64 = self.get_state().get_ticks();
374 
375         self.wrap_flag = 0;
376         self.cmp64 = self.calculate_cmp64(cur_tick, self.cmp);
377         if self.is_32bit_mod() {
378             // HPET spec says in one-shot 32-bit mode, generate an interrupt when
379             // counter wraps in addition to an interrupt with comparator match.
380             if !self.is_periodic() && self.cmp64 > hpet_next_wrap(cur_tick) {
381                 self.wrap_flag = 1;
382                 self.arm_timer(hpet_next_wrap(cur_tick));
383                 return;
384             }
385         }
386         self.arm_timer(self.cmp64);
387     }
388 
389     fn del_timer(&mut self) {
390         // Just remove the timer from the timer_list without destroying
391         // this timer instance.
392         self.qemu_timer.delete();
393 
394         if self.is_int_active() {
395             // For level-triggered interrupt, this leaves interrupt status
396             // register set but lowers irq.
397             self.update_irq(true);
398         }
399     }
400 
401     /// Configuration and Capability Register
402     fn set_tn_cfg_reg(&mut self, shift: u32, len: u32, val: u64) {
403         // TODO: Add trace point - trace_hpet_ram_write_tn_cfg(addr & 4)
404         let old_val: u64 = self.config;
405         let mut new_val: u64 = old_val.deposit(shift, len, val);
406         new_val = hpet_fixup_reg(new_val, old_val, HPET_TN_CFG_WRITE_MASK);
407 
408         // Switch level-type interrupt to edge-type.
409         if deactivating_bit(old_val, new_val, HPET_TN_CFG_INT_TYPE_SHIFT) {
410             // Do this before changing timer.config; otherwise, if
411             // HPET_TN_FSB is set, update_irq will not lower the qemu_irq.
412             self.update_irq(false);
413         }
414 
415         self.config = new_val;
416 
417         if activating_bit(old_val, new_val, HPET_TN_CFG_INT_ENABLE_SHIFT) && self.is_int_active() {
418             self.update_irq(true);
419         }
420 
421         if self.is_32bit_mod() {
422             self.cmp = u64::from(self.cmp as u32); // truncate!
423             self.period = u64::from(self.period as u32); // truncate!
424         }
425 
426         if self.get_state().is_hpet_enabled() {
427             self.set_timer();
428         }
429     }
430 
431     /// Comparator Value Register
432     fn set_tn_cmp_reg(&mut self, shift: u32, len: u32, val: u64) {
433         let mut length = len;
434         let mut value = val;
435 
436         // TODO: Add trace point - trace_hpet_ram_write_tn_cmp(addr & 4)
437         if self.is_32bit_mod() {
438             // High 32-bits are zero, leave them untouched.
439             if shift != 0 {
440                 // TODO: Add trace point - trace_hpet_ram_write_invalid_tn_cmp()
441                 return;
442             }
443             length = 64;
444             value = u64::from(value as u32); // truncate!
445         }
446 
447         if !self.is_periodic() || self.is_valset_enabled() {
448             self.cmp = self.cmp.deposit(shift, length, value);
449         }
450 
451         if self.is_periodic() {
452             self.period = self.period.deposit(shift, length, value);
453         }
454 
455         self.clear_valset();
456         if self.get_state().is_hpet_enabled() {
457             self.set_timer();
458         }
459     }
460 
461     /// FSB Interrupt Route Register
462     fn set_tn_fsb_route_reg(&mut self, shift: u32, len: u32, val: u64) {
463         self.fsb = self.fsb.deposit(shift, len, val);
464     }
465 
466     fn reset(&mut self) {
467         self.del_timer();
468         self.cmp = u64::MAX; // Comparator Match Registers reset to all 1's.
469         self.config = (1 << HPET_TN_CFG_PERIODIC_CAP_SHIFT) | (1 << HPET_TN_CFG_SIZE_CAP_SHIFT);
470         if self.get_state().has_msi_flag() {
471             self.config |= 1 << HPET_TN_CFG_FSB_CAP_SHIFT;
472         }
473         // advertise availability of ioapic int
474         self.config |=
475             (u64::from(self.get_state().int_route_cap)) << HPET_TN_CFG_INT_ROUTE_CAP_SHIFT;
476         self.period = 0;
477         self.wrap_flag = 0;
478     }
479 
480     /// timer expiration callback
481     fn callback(&mut self) {
482         let period: u64 = self.period;
483         let cur_tick: u64 = self.get_state().get_ticks();
484 
485         if self.is_periodic() && period != 0 {
486             while hpet_time_after(cur_tick, self.cmp64) {
487                 self.cmp64 += period;
488             }
489             if self.is_32bit_mod() {
490                 self.cmp = u64::from(self.cmp64 as u32); // truncate!
491             } else {
492                 self.cmp = self.cmp64;
493             }
494             self.arm_timer(self.cmp64);
495         } else if self.wrap_flag != 0 {
496             self.wrap_flag = 0;
497             self.arm_timer(self.cmp64);
498         }
499         self.update_irq(true);
500     }
501 
502     const fn read(&self, reg: TimerRegister) -> u64 {
503         use TimerRegister::*;
504         match reg {
505             CFG => self.config, // including interrupt capabilities
506             CMP => self.cmp,    // comparator register
507             ROUTE => self.fsb,
508         }
509     }
510 
511     fn write(&mut self, reg: TimerRegister, value: u64, shift: u32, len: u32) {
512         use TimerRegister::*;
513         match reg {
514             CFG => self.set_tn_cfg_reg(shift, len, value),
515             CMP => self.set_tn_cmp_reg(shift, len, value),
516             ROUTE => self.set_tn_fsb_route_reg(shift, len, value),
517         }
518     }
519 }
520 
521 /// HPET Event Timer Block Abstraction
522 #[repr(C)]
523 #[derive(qemu_api_macros::Object, qemu_api_macros::offsets)]
524 pub struct HPETState {
525     parent_obj: ParentField<SysBusDevice>,
526     iomem: MemoryRegion,
527 
528     // HPET block Registers: Memory-mapped, software visible registers
529     /// General Capabilities and ID Register
530     capability: BqlCell<u64>,
531     ///  General Configuration Register
532     config: BqlCell<u64>,
533     /// General Interrupt Status Register
534     #[doc(alias = "isr")]
535     int_status: BqlCell<u64>,
536     /// Main Counter Value Register
537     #[doc(alias = "hpet_counter")]
538     counter: BqlCell<u64>,
539 
540     // Internal state
541     /// Capabilities that QEMU HPET supports.
542     /// bit 0: MSI (or FSB) support.
543     flags: u32,
544 
545     /// Offset of main counter relative to qemu clock.
546     hpet_offset: BqlCell<u64>,
547     hpet_offset_saved: bool,
548 
549     irqs: [InterruptSource; HPET_NUM_IRQ_ROUTES],
550     rtc_irq_level: BqlCell<u32>,
551     pit_enabled: InterruptSource,
552 
553     /// Interrupt Routing Capability.
554     /// This field indicates to which interrupts in the I/O (x) APIC
555     /// the timers' interrupt can be routed, and is encoded in the
556     /// bits 32:64 of timer N's config register:
557     #[doc(alias = "intcap")]
558     int_route_cap: u32,
559 
560     /// HPET timer array managed by this timer block.
561     #[doc(alias = "timer")]
562     timers: [BqlRefCell<HPETTimer>; HPET_MAX_TIMERS],
563     num_timers: BqlCell<usize>,
564 
565     /// Instance id (HPET timer block ID).
566     hpet_id: BqlCell<usize>,
567 }
568 
569 impl HPETState {
570     const fn has_msi_flag(&self) -> bool {
571         self.flags & (1 << HPET_FLAG_MSI_SUPPORT_SHIFT) != 0
572     }
573 
574     fn is_legacy_mode(&self) -> bool {
575         self.config.get() & (1 << HPET_CFG_LEG_RT_SHIFT) != 0
576     }
577 
578     fn is_hpet_enabled(&self) -> bool {
579         self.config.get() & (1 << HPET_CFG_ENABLE_SHIFT) != 0
580     }
581 
582     fn is_timer_int_active(&self, index: usize) -> bool {
583         self.int_status.get() & (1 << index) != 0
584     }
585 
586     fn get_ticks(&self) -> u64 {
587         ns_to_ticks(CLOCK_VIRTUAL.get_ns() + self.hpet_offset.get())
588     }
589 
590     fn get_ns(&self, tick: u64) -> u64 {
591         ticks_to_ns(tick) - self.hpet_offset.get()
592     }
593 
594     fn handle_legacy_irq(&self, irq: u32, level: u32) {
595         if irq == HPET_LEGACY_PIT_INT {
596             if !self.is_legacy_mode() {
597                 self.irqs[0].set(level != 0);
598             }
599         } else {
600             self.rtc_irq_level.set(level);
601             if !self.is_legacy_mode() {
602                 self.irqs[RTC_ISA_IRQ].set(level != 0);
603             }
604         }
605     }
606 
607     fn init_timer(&self) {
608         for (index, timer) in self.timers.iter().enumerate() {
609             timer.borrow_mut().init(index, self);
610         }
611     }
612 
613     fn update_int_status(&self, index: u32, level: bool) {
614         self.int_status
615             .set(self.int_status.get().deposit(index, 1, u64::from(level)));
616     }
617 
618     /// General Configuration Register
619     fn set_cfg_reg(&self, shift: u32, len: u32, val: u64) {
620         let old_val = self.config.get();
621         let mut new_val = old_val.deposit(shift, len, val);
622 
623         new_val = hpet_fixup_reg(new_val, old_val, HPET_CFG_WRITE_MASK);
624         self.config.set(new_val);
625 
626         if activating_bit(old_val, new_val, HPET_CFG_ENABLE_SHIFT) {
627             // Enable main counter and interrupt generation.
628             self.hpet_offset
629                 .set(ticks_to_ns(self.counter.get()) - CLOCK_VIRTUAL.get_ns());
630 
631             for timer in self.timers.iter().take(self.num_timers.get()) {
632                 let mut t = timer.borrow_mut();
633 
634                 if t.is_int_enabled() && t.is_int_active() {
635                     t.update_irq(true);
636                 }
637                 t.set_timer();
638             }
639         } else if deactivating_bit(old_val, new_val, HPET_CFG_ENABLE_SHIFT) {
640             // Halt main counter and disable interrupt generation.
641             self.counter.set(self.get_ticks());
642 
643             for timer in self.timers.iter().take(self.num_timers.get()) {
644                 timer.borrow_mut().del_timer();
645             }
646         }
647 
648         // i8254 and RTC output pins are disabled when HPET is in legacy mode
649         if activating_bit(old_val, new_val, HPET_CFG_LEG_RT_SHIFT) {
650             self.pit_enabled.set(false);
651             self.irqs[0].lower();
652             self.irqs[RTC_ISA_IRQ].lower();
653         } else if deactivating_bit(old_val, new_val, HPET_CFG_LEG_RT_SHIFT) {
654             // TODO: Add irq binding: qemu_irq_lower(s->irqs[0])
655             self.irqs[0].lower();
656             self.pit_enabled.set(true);
657             self.irqs[RTC_ISA_IRQ].set(self.rtc_irq_level.get() != 0);
658         }
659     }
660 
661     /// General Interrupt Status Register: Read/Write Clear
662     fn set_int_status_reg(&self, shift: u32, _len: u32, val: u64) {
663         let new_val = val << shift;
664         let cleared = new_val & self.int_status.get();
665 
666         for (index, timer) in self.timers.iter().take(self.num_timers.get()).enumerate() {
667             if cleared & (1 << index) != 0 {
668                 timer.borrow_mut().update_irq(false);
669             }
670         }
671     }
672 
673     /// Main Counter Value Register
674     fn set_counter_reg(&self, shift: u32, len: u32, val: u64) {
675         if self.is_hpet_enabled() {
676             // TODO: Add trace point -
677             // trace_hpet_ram_write_counter_write_while_enabled()
678             //
679             // HPET spec says that writes to this register should only be
680             // done while the counter is halted. So this is an undefined
681             // behavior. There's no need to forbid it, but when HPET is
682             // enabled, the changed counter value will not affect the
683             // tick count (i.e., the previously calculated offset will
684             // not be changed as well).
685         }
686         self.counter
687             .set(self.counter.get().deposit(shift, len, val));
688     }
689 
690     unsafe fn init(&mut self) {
691         static HPET_RAM_OPS: MemoryRegionOps<HPETState> =
692             MemoryRegionOpsBuilder::<HPETState>::new()
693                 .read(&HPETState::read)
694                 .write(&HPETState::write)
695                 .native_endian()
696                 .valid_sizes(4, 8)
697                 .impl_sizes(4, 8)
698                 .build();
699 
700         // SAFETY:
701         // self and self.iomem are guaranteed to be valid at this point since callers
702         // must make sure the `self` reference is valid.
703         MemoryRegion::init_io(
704             unsafe { &mut *addr_of_mut!(self.iomem) },
705             addr_of_mut!(*self),
706             &HPET_RAM_OPS,
707             "hpet",
708             HPET_REG_SPACE_LEN,
709         );
710     }
711 
712     fn post_init(&self) {
713         self.init_mmio(&self.iomem);
714         for irq in self.irqs.iter() {
715             self.init_irq(irq);
716         }
717     }
718 
719     fn realize(&self) {
720         if self.int_route_cap == 0 {
721             // TODO: Add error binding: warn_report()
722             println!("Hpet's hpet-intcap property not initialized");
723         }
724 
725         self.hpet_id.set(HPETFwConfig::assign_hpet_id());
726 
727         if self.num_timers.get() < HPET_MIN_TIMERS {
728             self.num_timers.set(HPET_MIN_TIMERS);
729         } else if self.num_timers.get() > HPET_MAX_TIMERS {
730             self.num_timers.set(HPET_MAX_TIMERS);
731         }
732 
733         self.init_timer();
734         // 64-bit General Capabilities and ID Register; LegacyReplacementRoute.
735         self.capability.set(
736             HPET_CAP_REV_ID_VALUE << HPET_CAP_REV_ID_SHIFT |
737             1 << HPET_CAP_COUNT_SIZE_CAP_SHIFT |
738             1 << HPET_CAP_LEG_RT_CAP_SHIFT |
739             HPET_CAP_VENDER_ID_VALUE << HPET_CAP_VENDER_ID_SHIFT |
740             ((self.num_timers.get() - 1) as u64) << HPET_CAP_NUM_TIM_SHIFT | // indicate the last timer
741             (HPET_CLK_PERIOD * FS_PER_NS) << HPET_CAP_CNT_CLK_PERIOD_SHIFT, // 10 ns
742         );
743 
744         self.init_gpio_in(2, HPETState::handle_legacy_irq);
745         self.init_gpio_out(from_ref(&self.pit_enabled));
746     }
747 
748     fn reset_hold(&self, _type: ResetType) {
749         for timer in self.timers.iter().take(self.num_timers.get()) {
750             timer.borrow_mut().reset();
751         }
752 
753         self.counter.set(0);
754         self.config.set(0);
755         self.pit_enabled.set(true);
756         self.hpet_offset.set(0);
757 
758         HPETFwConfig::update_hpet_cfg(
759             self.hpet_id.get(),
760             self.capability.get() as u32,
761             self.mmio_addr(0).unwrap(),
762         );
763 
764         // to document that the RTC lowers its output on reset as well
765         self.rtc_irq_level.set(0);
766     }
767 
768     fn decode(&self, mut addr: hwaddr, size: u32) -> HPETAddrDecode {
769         let shift = ((addr & 4) * 8) as u32;
770         let len = std::cmp::min(size * 8, 64 - shift);
771 
772         addr &= !4;
773         let reg = if (0..=0xff).contains(&addr) {
774             GlobalRegister::try_from(addr).map(HPETRegister::Global)
775         } else {
776             let timer_id: usize = ((addr - 0x100) / 0x20) as usize;
777             if timer_id <= self.num_timers.get() {
778                 // TODO: Add trace point - trace_hpet_ram_[read|write]_timer_id(timer_id)
779                 TimerRegister::try_from(addr)
780                     .map(|reg| HPETRegister::Timer(&self.timers[timer_id], reg))
781             } else {
782                 // TODO: Add trace point -  trace_hpet_timer_id_out_of_range(timer_id)
783                 Err(addr)
784             }
785         };
786 
787         // reg is now a Result<HPETRegister, hwaddr>
788         // convert the Err case into HPETRegister as well
789         let reg = reg.unwrap_or_else(HPETRegister::Unknown);
790         HPETAddrDecode { shift, len, reg }
791     }
792 
793     fn read(&self, addr: hwaddr, size: u32) -> u64 {
794         // TODO: Add trace point - trace_hpet_ram_read(addr)
795         let HPETAddrDecode { shift, reg, .. } = self.decode(addr, size);
796 
797         use GlobalRegister::*;
798         use HPETRegister::*;
799         (match reg {
800             Timer(timer, tn_reg) => timer.borrow_mut().read(tn_reg),
801             Global(CAP) => self.capability.get(), /* including HPET_PERIOD 0x004 */
802             Global(CFG) => self.config.get(),
803             Global(INT_STATUS) => self.int_status.get(),
804             Global(COUNTER) => {
805                 // TODO: Add trace point
806                 // trace_hpet_ram_read_reading_counter(addr & 4, cur_tick)
807                 if self.is_hpet_enabled() {
808                     self.get_ticks()
809                 } else {
810                     self.counter.get()
811                 }
812             }
813             Unknown(_) => {
814                 // TODO: Add trace point- trace_hpet_ram_read_invalid()
815                 0
816             }
817         }) >> shift
818     }
819 
820     fn write(&self, addr: hwaddr, value: u64, size: u32) {
821         let HPETAddrDecode { shift, len, reg } = self.decode(addr, size);
822 
823         // TODO: Add trace point - trace_hpet_ram_write(addr, value)
824         use GlobalRegister::*;
825         use HPETRegister::*;
826         match reg {
827             Timer(timer, tn_reg) => timer.borrow_mut().write(tn_reg, value, shift, len),
828             Global(CAP) => {} // General Capabilities and ID Register: Read Only
829             Global(CFG) => self.set_cfg_reg(shift, len, value),
830             Global(INT_STATUS) => self.set_int_status_reg(shift, len, value),
831             Global(COUNTER) => self.set_counter_reg(shift, len, value),
832             Unknown(_) => {
833                 // TODO: Add trace point - trace_hpet_ram_write_invalid()
834             }
835         }
836     }
837 }
838 
839 qom_isa!(HPETState: SysBusDevice, DeviceState, Object);
840 
841 unsafe impl ObjectType for HPETState {
842     // No need for HPETClass. Just like OBJECT_DECLARE_SIMPLE_TYPE in C.
843     type Class = <SysBusDevice as ObjectType>::Class;
844     const TYPE_NAME: &'static CStr = crate::TYPE_HPET;
845 }
846 
847 impl ObjectImpl for HPETState {
848     type ParentType = SysBusDevice;
849 
850     const INSTANCE_INIT: Option<unsafe fn(&mut Self)> = Some(Self::init);
851     const INSTANCE_POST_INIT: Option<fn(&Self)> = Some(Self::post_init);
852     const CLASS_INIT: fn(&mut Self::Class) = Self::Class::class_init::<Self>;
853 }
854 
855 // TODO: Make these properties user-configurable!
856 qemu_api::declare_properties! {
857     HPET_PROPERTIES,
858     qemu_api::define_property!(
859         c_str!("timers"),
860         HPETState,
861         num_timers,
862         unsafe { &qdev_prop_usize },
863         usize,
864         default = HPET_MIN_TIMERS
865     ),
866     qemu_api::define_property!(
867         c_str!("msi"),
868         HPETState,
869         flags,
870         unsafe { &qdev_prop_bit },
871         u32,
872         bit = HPET_FLAG_MSI_SUPPORT_SHIFT as u8,
873         default = false,
874     ),
875     qemu_api::define_property!(
876         c_str!("hpet-intcap"),
877         HPETState,
878         int_route_cap,
879         unsafe { &qdev_prop_uint32 },
880         u32,
881         default = 0
882     ),
883     qemu_api::define_property!(
884         c_str!("hpet-offset-saved"),
885         HPETState,
886         hpet_offset_saved,
887         unsafe { &qdev_prop_bool },
888         bool,
889         default = true
890     ),
891 }
892 
893 impl DeviceImpl for HPETState {
894     fn properties() -> &'static [Property] {
895         &HPET_PROPERTIES
896     }
897 
898     const REALIZE: Option<fn(&Self)> = Some(Self::realize);
899 }
900 
901 impl ResettablePhasesImpl for HPETState {
902     const HOLD: Option<fn(&Self, ResetType)> = Some(Self::reset_hold);
903 }
904 
905 impl SysBusDeviceImpl for HPETState {}
906