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