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