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