1734a1e9eSPaolo Bonzini // Copyright (C) 2024 Intel Corporation. 2734a1e9eSPaolo Bonzini // Author(s): Zhao Liu <zhao1.liu@intel.com> 3734a1e9eSPaolo Bonzini // SPDX-License-Identifier: GPL-2.0-or-later 4734a1e9eSPaolo Bonzini 5734a1e9eSPaolo Bonzini use std::{ 6734a1e9eSPaolo Bonzini ffi::{c_int, c_void, CStr}, 7734a1e9eSPaolo Bonzini pin::Pin, 8734a1e9eSPaolo Bonzini ptr::{addr_of_mut, null_mut, NonNull}, 9734a1e9eSPaolo Bonzini slice::from_ref, 10734a1e9eSPaolo Bonzini }; 11734a1e9eSPaolo Bonzini 12734a1e9eSPaolo Bonzini use qemu_api::{ 13734a1e9eSPaolo Bonzini bindings::{ 14734a1e9eSPaolo Bonzini address_space_memory, address_space_stl_le, qdev_prop_bit, qdev_prop_bool, 15b3bf86b8SPaolo Bonzini qdev_prop_uint32, qdev_prop_usize, 16734a1e9eSPaolo Bonzini }, 17734a1e9eSPaolo Bonzini cell::{BqlCell, BqlRefCell}, 18734a1e9eSPaolo Bonzini irq::InterruptSource, 19734a1e9eSPaolo Bonzini memory::{ 20734a1e9eSPaolo Bonzini hwaddr, MemoryRegion, MemoryRegionOps, MemoryRegionOpsBuilder, MEMTXATTRS_UNSPECIFIED, 21734a1e9eSPaolo Bonzini }, 22734a1e9eSPaolo Bonzini prelude::*, 23734a1e9eSPaolo Bonzini qdev::{DeviceImpl, DeviceMethods, DeviceState, Property, ResetType, ResettablePhasesImpl}, 24734a1e9eSPaolo Bonzini qom::{ObjectImpl, ObjectType, ParentField}, 25734a1e9eSPaolo Bonzini qom_isa, 26734a1e9eSPaolo Bonzini sysbus::{SysBusDevice, SysBusDeviceImpl}, 27734a1e9eSPaolo Bonzini timer::{Timer, CLOCK_VIRTUAL, NANOSECONDS_PER_SECOND}, 28734a1e9eSPaolo Bonzini vmstate::VMStateDescription, 29734a1e9eSPaolo Bonzini vmstate_fields, vmstate_of, vmstate_struct, vmstate_subsections, vmstate_validate, 30734a1e9eSPaolo Bonzini zeroable::Zeroable, 31734a1e9eSPaolo Bonzini }; 32734a1e9eSPaolo Bonzini 33734a1e9eSPaolo Bonzini use crate::fw_cfg::HPETFwConfig; 34734a1e9eSPaolo Bonzini 35734a1e9eSPaolo Bonzini /// Register space for each timer block (`HPET_BASE` is defined in hpet.h). 36734a1e9eSPaolo Bonzini const HPET_REG_SPACE_LEN: u64 = 0x400; // 1024 bytes 37734a1e9eSPaolo Bonzini 38734a1e9eSPaolo Bonzini /// Minimum recommended hardware implementation. 39b3bf86b8SPaolo Bonzini const HPET_MIN_TIMERS: usize = 3; 40734a1e9eSPaolo Bonzini /// Maximum timers in each timer block. 41b3bf86b8SPaolo Bonzini const HPET_MAX_TIMERS: usize = 32; 42734a1e9eSPaolo Bonzini 43734a1e9eSPaolo Bonzini /// Flags that HPETState.flags supports. 44734a1e9eSPaolo Bonzini const HPET_FLAG_MSI_SUPPORT_SHIFT: usize = 0; 45734a1e9eSPaolo Bonzini 46734a1e9eSPaolo Bonzini const HPET_NUM_IRQ_ROUTES: usize = 32; 47734a1e9eSPaolo Bonzini const HPET_LEGACY_PIT_INT: u32 = 0; // HPET_LEGACY_RTC_INT isn't defined here. 48734a1e9eSPaolo Bonzini const RTC_ISA_IRQ: usize = 8; 49734a1e9eSPaolo Bonzini 50734a1e9eSPaolo Bonzini const HPET_CLK_PERIOD: u64 = 10; // 10 ns 51734a1e9eSPaolo Bonzini const FS_PER_NS: u64 = 1000000; // 1000000 femtoseconds == 1 ns 52734a1e9eSPaolo Bonzini 53734a1e9eSPaolo Bonzini /// Revision ID (bits 0:7). Revision 1 is implemented (refer to v1.0a spec). 54734a1e9eSPaolo Bonzini const HPET_CAP_REV_ID_VALUE: u64 = 0x1; 55734a1e9eSPaolo Bonzini const HPET_CAP_REV_ID_SHIFT: usize = 0; 56734a1e9eSPaolo Bonzini /// Number of Timers (bits 8:12) 57734a1e9eSPaolo Bonzini const HPET_CAP_NUM_TIM_SHIFT: usize = 8; 58734a1e9eSPaolo Bonzini /// Counter Size (bit 13) 59734a1e9eSPaolo Bonzini const HPET_CAP_COUNT_SIZE_CAP_SHIFT: usize = 13; 60734a1e9eSPaolo Bonzini /// Legacy Replacement Route Capable (bit 15) 61734a1e9eSPaolo Bonzini const HPET_CAP_LEG_RT_CAP_SHIFT: usize = 15; 62734a1e9eSPaolo Bonzini /// Vendor ID (bits 16:31) 63734a1e9eSPaolo Bonzini const HPET_CAP_VENDER_ID_VALUE: u64 = 0x8086; 64734a1e9eSPaolo Bonzini const HPET_CAP_VENDER_ID_SHIFT: usize = 16; 65734a1e9eSPaolo Bonzini /// Main Counter Tick Period (bits 32:63) 66734a1e9eSPaolo Bonzini const HPET_CAP_CNT_CLK_PERIOD_SHIFT: usize = 32; 67734a1e9eSPaolo Bonzini 68734a1e9eSPaolo Bonzini /// Overall Enable (bit 0) 69734a1e9eSPaolo Bonzini const HPET_CFG_ENABLE_SHIFT: usize = 0; 70734a1e9eSPaolo Bonzini /// Legacy Replacement Route (bit 1) 71734a1e9eSPaolo Bonzini const HPET_CFG_LEG_RT_SHIFT: usize = 1; 72734a1e9eSPaolo Bonzini /// Other bits are reserved. 73734a1e9eSPaolo Bonzini const HPET_CFG_WRITE_MASK: u64 = 0x003; 74734a1e9eSPaolo Bonzini 75734a1e9eSPaolo Bonzini /// bit 0, 7, and bits 16:31 are reserved. 76734a1e9eSPaolo Bonzini /// bit 4, 5, 15, and bits 32:64 are read-only. 77734a1e9eSPaolo Bonzini const HPET_TN_CFG_WRITE_MASK: u64 = 0x7f4e; 78734a1e9eSPaolo Bonzini /// Timer N Interrupt Type (bit 1) 79734a1e9eSPaolo Bonzini const HPET_TN_CFG_INT_TYPE_SHIFT: usize = 1; 80734a1e9eSPaolo Bonzini /// Timer N Interrupt Enable (bit 2) 81734a1e9eSPaolo Bonzini const HPET_TN_CFG_INT_ENABLE_SHIFT: usize = 2; 82734a1e9eSPaolo Bonzini /// Timer N Type (Periodic enabled or not, bit 3) 83734a1e9eSPaolo Bonzini const HPET_TN_CFG_PERIODIC_SHIFT: usize = 3; 84734a1e9eSPaolo Bonzini /// Timer N Periodic Interrupt Capable (support Periodic or not, bit 4) 85734a1e9eSPaolo Bonzini const HPET_TN_CFG_PERIODIC_CAP_SHIFT: usize = 4; 86734a1e9eSPaolo Bonzini /// Timer N Size (timer size is 64-bits or 32 bits, bit 5) 87734a1e9eSPaolo Bonzini const HPET_TN_CFG_SIZE_CAP_SHIFT: usize = 5; 88734a1e9eSPaolo Bonzini /// Timer N Value Set (bit 6) 89734a1e9eSPaolo Bonzini const HPET_TN_CFG_SETVAL_SHIFT: usize = 6; 90734a1e9eSPaolo Bonzini /// Timer N 32-bit Mode (bit 8) 91734a1e9eSPaolo Bonzini const HPET_TN_CFG_32BIT_SHIFT: usize = 8; 92734a1e9eSPaolo Bonzini /// Timer N Interrupt Rout (bits 9:13) 93734a1e9eSPaolo Bonzini const HPET_TN_CFG_INT_ROUTE_MASK: u64 = 0x3e00; 94734a1e9eSPaolo Bonzini const HPET_TN_CFG_INT_ROUTE_SHIFT: usize = 9; 95734a1e9eSPaolo Bonzini /// Timer N FSB Interrupt Enable (bit 14) 96734a1e9eSPaolo Bonzini const HPET_TN_CFG_FSB_ENABLE_SHIFT: usize = 14; 97734a1e9eSPaolo Bonzini /// Timer N FSB Interrupt Delivery (bit 15) 98734a1e9eSPaolo Bonzini const HPET_TN_CFG_FSB_CAP_SHIFT: usize = 15; 99734a1e9eSPaolo Bonzini /// Timer N Interrupt Routing Capability (bits 32:63) 100734a1e9eSPaolo Bonzini const HPET_TN_CFG_INT_ROUTE_CAP_SHIFT: usize = 32; 101734a1e9eSPaolo Bonzini 102734a1e9eSPaolo Bonzini #[derive(qemu_api_macros::TryInto)] 103734a1e9eSPaolo Bonzini #[repr(u64)] 104734a1e9eSPaolo Bonzini #[allow(non_camel_case_types)] 105734a1e9eSPaolo Bonzini /// Timer registers, masked by 0x18 106734a1e9eSPaolo Bonzini enum TimerRegister { 107734a1e9eSPaolo Bonzini /// Timer N Configuration and Capability Register 108734a1e9eSPaolo Bonzini CFG = 0, 109734a1e9eSPaolo Bonzini /// Timer N Comparator Value Register 110734a1e9eSPaolo Bonzini CMP = 8, 111734a1e9eSPaolo Bonzini /// Timer N FSB Interrupt Route Register 112734a1e9eSPaolo Bonzini ROUTE = 16, 113734a1e9eSPaolo Bonzini } 114734a1e9eSPaolo Bonzini 115734a1e9eSPaolo Bonzini #[derive(qemu_api_macros::TryInto)] 116734a1e9eSPaolo Bonzini #[repr(u64)] 117734a1e9eSPaolo Bonzini #[allow(non_camel_case_types)] 118734a1e9eSPaolo Bonzini /// Global registers 119734a1e9eSPaolo Bonzini enum GlobalRegister { 120734a1e9eSPaolo Bonzini /// General Capabilities and ID Register 121734a1e9eSPaolo Bonzini CAP = 0, 122734a1e9eSPaolo Bonzini /// General Configuration Register 123734a1e9eSPaolo Bonzini CFG = 0x10, 124734a1e9eSPaolo Bonzini /// General Interrupt Status Register 125734a1e9eSPaolo Bonzini INT_STATUS = 0x20, 126734a1e9eSPaolo Bonzini /// Main Counter Value Register 127734a1e9eSPaolo Bonzini COUNTER = 0xF0, 128734a1e9eSPaolo Bonzini } 129734a1e9eSPaolo Bonzini 130734a1e9eSPaolo Bonzini enum HPETRegister<'a> { 131734a1e9eSPaolo Bonzini /// Global register in the range from `0` to `0xff` 132734a1e9eSPaolo Bonzini Global(GlobalRegister), 133734a1e9eSPaolo Bonzini 134734a1e9eSPaolo Bonzini /// Register in the timer block `0x100`...`0x3ff` 135734a1e9eSPaolo Bonzini Timer(&'a BqlRefCell<HPETTimer>, TimerRegister), 136734a1e9eSPaolo Bonzini 137734a1e9eSPaolo Bonzini /// Invalid address 138734a1e9eSPaolo Bonzini #[allow(dead_code)] 139734a1e9eSPaolo Bonzini Unknown(hwaddr), 140734a1e9eSPaolo Bonzini } 141734a1e9eSPaolo Bonzini 142734a1e9eSPaolo Bonzini struct HPETAddrDecode<'a> { 143734a1e9eSPaolo Bonzini shift: u32, 144734a1e9eSPaolo Bonzini len: u32, 145734a1e9eSPaolo Bonzini reg: HPETRegister<'a>, 146734a1e9eSPaolo Bonzini } 147734a1e9eSPaolo Bonzini 148734a1e9eSPaolo Bonzini const fn hpet_next_wrap(cur_tick: u64) -> u64 { 149734a1e9eSPaolo Bonzini (cur_tick | 0xffffffff) + 1 150734a1e9eSPaolo Bonzini } 151734a1e9eSPaolo Bonzini 152734a1e9eSPaolo Bonzini const fn hpet_time_after(a: u64, b: u64) -> bool { 153734a1e9eSPaolo Bonzini ((b - a) as i64) < 0 154734a1e9eSPaolo Bonzini } 155734a1e9eSPaolo Bonzini 156734a1e9eSPaolo Bonzini const fn ticks_to_ns(value: u64) -> u64 { 157734a1e9eSPaolo Bonzini value * HPET_CLK_PERIOD 158734a1e9eSPaolo Bonzini } 159734a1e9eSPaolo Bonzini 160734a1e9eSPaolo Bonzini const fn ns_to_ticks(value: u64) -> u64 { 161734a1e9eSPaolo Bonzini value / HPET_CLK_PERIOD 162734a1e9eSPaolo Bonzini } 163734a1e9eSPaolo Bonzini 164734a1e9eSPaolo Bonzini // Avoid touching the bits that cannot be written. 165734a1e9eSPaolo Bonzini const fn hpet_fixup_reg(new: u64, old: u64, mask: u64) -> u64 { 166734a1e9eSPaolo Bonzini (new & mask) | (old & !mask) 167734a1e9eSPaolo Bonzini } 168734a1e9eSPaolo Bonzini 169734a1e9eSPaolo Bonzini const fn activating_bit(old: u64, new: u64, shift: usize) -> bool { 170734a1e9eSPaolo Bonzini let mask: u64 = 1 << shift; 171734a1e9eSPaolo Bonzini (old & mask == 0) && (new & mask != 0) 172734a1e9eSPaolo Bonzini } 173734a1e9eSPaolo Bonzini 174734a1e9eSPaolo Bonzini const fn deactivating_bit(old: u64, new: u64, shift: usize) -> bool { 175734a1e9eSPaolo Bonzini let mask: u64 = 1 << shift; 176734a1e9eSPaolo Bonzini (old & mask != 0) && (new & mask == 0) 177734a1e9eSPaolo Bonzini } 178734a1e9eSPaolo Bonzini 179734a1e9eSPaolo Bonzini fn timer_handler(timer_cell: &BqlRefCell<HPETTimer>) { 180734a1e9eSPaolo Bonzini timer_cell.borrow_mut().callback() 181734a1e9eSPaolo Bonzini } 182734a1e9eSPaolo Bonzini 183734a1e9eSPaolo Bonzini /// HPET Timer Abstraction 184734a1e9eSPaolo Bonzini #[repr(C)] 185734a1e9eSPaolo Bonzini #[derive(Debug)] 186734a1e9eSPaolo Bonzini pub struct HPETTimer { 187734a1e9eSPaolo Bonzini /// timer N index within the timer block (`HPETState`) 188734a1e9eSPaolo Bonzini #[doc(alias = "tn")] 189734a1e9eSPaolo Bonzini index: u8, 190734a1e9eSPaolo Bonzini qemu_timer: Timer, 191734a1e9eSPaolo Bonzini /// timer block abstraction containing this timer 192734a1e9eSPaolo Bonzini state: NonNull<HPETState>, 193734a1e9eSPaolo Bonzini 194734a1e9eSPaolo Bonzini // Memory-mapped, software visible timer registers 195734a1e9eSPaolo Bonzini /// Timer N Configuration and Capability Register 196734a1e9eSPaolo Bonzini config: u64, 197734a1e9eSPaolo Bonzini /// Timer N Comparator Value Register 198734a1e9eSPaolo Bonzini cmp: u64, 199734a1e9eSPaolo Bonzini /// Timer N FSB Interrupt Route Register 200734a1e9eSPaolo Bonzini fsb: u64, 201734a1e9eSPaolo Bonzini 202734a1e9eSPaolo Bonzini // Hidden register state 203734a1e9eSPaolo Bonzini /// comparator (extended to counter width) 204734a1e9eSPaolo Bonzini cmp64: u64, 205734a1e9eSPaolo Bonzini /// Last value written to comparator 206734a1e9eSPaolo Bonzini period: u64, 207734a1e9eSPaolo Bonzini /// timer pop will indicate wrap for one-shot 32-bit 208734a1e9eSPaolo Bonzini /// mode. Next pop will be actual timer expiration. 209734a1e9eSPaolo Bonzini wrap_flag: u8, 210734a1e9eSPaolo Bonzini /// last value armed, to avoid timer storms 211734a1e9eSPaolo Bonzini last: u64, 212734a1e9eSPaolo Bonzini } 213734a1e9eSPaolo Bonzini 214734a1e9eSPaolo Bonzini impl HPETTimer { 215734a1e9eSPaolo Bonzini fn init(&mut self, index: u8, state: &HPETState) { 216734a1e9eSPaolo Bonzini *self = HPETTimer { 217734a1e9eSPaolo Bonzini index, 218734a1e9eSPaolo Bonzini // SAFETY: the HPETTimer will only be used after the timer 219734a1e9eSPaolo Bonzini // is initialized below. 220734a1e9eSPaolo Bonzini qemu_timer: unsafe { Timer::new() }, 221734a1e9eSPaolo Bonzini state: NonNull::new((state as *const HPETState).cast_mut()).unwrap(), 222734a1e9eSPaolo Bonzini config: 0, 223734a1e9eSPaolo Bonzini cmp: 0, 224734a1e9eSPaolo Bonzini fsb: 0, 225734a1e9eSPaolo Bonzini cmp64: 0, 226734a1e9eSPaolo Bonzini period: 0, 227734a1e9eSPaolo Bonzini wrap_flag: 0, 228734a1e9eSPaolo Bonzini last: 0, 229734a1e9eSPaolo Bonzini }; 230734a1e9eSPaolo Bonzini 231734a1e9eSPaolo Bonzini // SAFETY: HPETTimer is only used as part of HPETState, which is 232734a1e9eSPaolo Bonzini // always pinned. 233734a1e9eSPaolo Bonzini let qemu_timer = unsafe { Pin::new_unchecked(&mut self.qemu_timer) }; 234734a1e9eSPaolo Bonzini qemu_timer.init_full( 235734a1e9eSPaolo Bonzini None, 236734a1e9eSPaolo Bonzini CLOCK_VIRTUAL, 237734a1e9eSPaolo Bonzini Timer::NS, 238734a1e9eSPaolo Bonzini 0, 239734a1e9eSPaolo Bonzini timer_handler, 240734a1e9eSPaolo Bonzini &state.timers[self.index as usize], 241734a1e9eSPaolo Bonzini ) 242734a1e9eSPaolo Bonzini } 243734a1e9eSPaolo Bonzini 244734a1e9eSPaolo Bonzini fn get_state(&self) -> &HPETState { 245734a1e9eSPaolo Bonzini // SAFETY: 246734a1e9eSPaolo Bonzini // the pointer is convertible to a reference 247734a1e9eSPaolo Bonzini unsafe { self.state.as_ref() } 248734a1e9eSPaolo Bonzini } 249734a1e9eSPaolo Bonzini 250734a1e9eSPaolo Bonzini fn is_int_active(&self) -> bool { 251734a1e9eSPaolo Bonzini self.get_state().is_timer_int_active(self.index.into()) 252734a1e9eSPaolo Bonzini } 253734a1e9eSPaolo Bonzini 254734a1e9eSPaolo Bonzini const fn is_fsb_route_enabled(&self) -> bool { 255734a1e9eSPaolo Bonzini self.config & (1 << HPET_TN_CFG_FSB_ENABLE_SHIFT) != 0 256734a1e9eSPaolo Bonzini } 257734a1e9eSPaolo Bonzini 258734a1e9eSPaolo Bonzini const fn is_periodic(&self) -> bool { 259734a1e9eSPaolo Bonzini self.config & (1 << HPET_TN_CFG_PERIODIC_SHIFT) != 0 260734a1e9eSPaolo Bonzini } 261734a1e9eSPaolo Bonzini 262734a1e9eSPaolo Bonzini const fn is_int_enabled(&self) -> bool { 263734a1e9eSPaolo Bonzini self.config & (1 << HPET_TN_CFG_INT_ENABLE_SHIFT) != 0 264734a1e9eSPaolo Bonzini } 265734a1e9eSPaolo Bonzini 266734a1e9eSPaolo Bonzini const fn is_32bit_mod(&self) -> bool { 267734a1e9eSPaolo Bonzini self.config & (1 << HPET_TN_CFG_32BIT_SHIFT) != 0 268734a1e9eSPaolo Bonzini } 269734a1e9eSPaolo Bonzini 270734a1e9eSPaolo Bonzini const fn is_valset_enabled(&self) -> bool { 271734a1e9eSPaolo Bonzini self.config & (1 << HPET_TN_CFG_SETVAL_SHIFT) != 0 272734a1e9eSPaolo Bonzini } 273734a1e9eSPaolo Bonzini 274734a1e9eSPaolo Bonzini fn clear_valset(&mut self) { 275734a1e9eSPaolo Bonzini self.config &= !(1 << HPET_TN_CFG_SETVAL_SHIFT); 276734a1e9eSPaolo Bonzini } 277734a1e9eSPaolo Bonzini 278734a1e9eSPaolo Bonzini /// True if timer interrupt is level triggered; otherwise, edge triggered. 279734a1e9eSPaolo Bonzini const fn is_int_level_triggered(&self) -> bool { 280734a1e9eSPaolo Bonzini self.config & (1 << HPET_TN_CFG_INT_TYPE_SHIFT) != 0 281734a1e9eSPaolo Bonzini } 282734a1e9eSPaolo Bonzini 283734a1e9eSPaolo Bonzini /// calculate next value of the general counter that matches the 284734a1e9eSPaolo Bonzini /// target (either entirely, or the low 32-bit only depending on 285734a1e9eSPaolo Bonzini /// the timer mode). 286734a1e9eSPaolo Bonzini fn calculate_cmp64(&self, cur_tick: u64, target: u64) -> u64 { 287734a1e9eSPaolo Bonzini if self.is_32bit_mod() { 288734a1e9eSPaolo Bonzini let mut result: u64 = cur_tick.deposit(0, 32, target); 289734a1e9eSPaolo Bonzini if result < cur_tick { 290734a1e9eSPaolo Bonzini result += 0x100000000; 291734a1e9eSPaolo Bonzini } 292734a1e9eSPaolo Bonzini result 293734a1e9eSPaolo Bonzini } else { 294734a1e9eSPaolo Bonzini target 295734a1e9eSPaolo Bonzini } 296734a1e9eSPaolo Bonzini } 297734a1e9eSPaolo Bonzini 298734a1e9eSPaolo Bonzini const fn get_individual_route(&self) -> usize { 299734a1e9eSPaolo Bonzini ((self.config & HPET_TN_CFG_INT_ROUTE_MASK) >> HPET_TN_CFG_INT_ROUTE_SHIFT) as usize 300734a1e9eSPaolo Bonzini } 301734a1e9eSPaolo Bonzini 302734a1e9eSPaolo Bonzini fn get_int_route(&self) -> usize { 303734a1e9eSPaolo Bonzini if self.index <= 1 && self.get_state().is_legacy_mode() { 304734a1e9eSPaolo Bonzini // If LegacyReplacement Route bit is set, HPET specification requires 305734a1e9eSPaolo Bonzini // timer0 be routed to IRQ0 in NON-APIC or IRQ2 in the I/O APIC, 306734a1e9eSPaolo Bonzini // timer1 be routed to IRQ8 in NON-APIC or IRQ8 in the I/O APIC. 307734a1e9eSPaolo Bonzini // 308734a1e9eSPaolo Bonzini // If the LegacyReplacement Route bit is set, the individual routing 309734a1e9eSPaolo Bonzini // bits for timers 0 and 1 (APIC or FSB) will have no impact. 310734a1e9eSPaolo Bonzini // 311734a1e9eSPaolo Bonzini // FIXME: Consider I/O APIC case. 312734a1e9eSPaolo Bonzini if self.index == 0 { 313734a1e9eSPaolo Bonzini 0 314734a1e9eSPaolo Bonzini } else { 315734a1e9eSPaolo Bonzini RTC_ISA_IRQ 316734a1e9eSPaolo Bonzini } 317734a1e9eSPaolo Bonzini } else { 318734a1e9eSPaolo Bonzini // (If the LegacyReplacement Route bit is set) Timer 2-n will be 319734a1e9eSPaolo Bonzini // routed as per the routing in the timer n config registers. 320734a1e9eSPaolo Bonzini // ... 321734a1e9eSPaolo Bonzini // If the LegacyReplacement Route bit is not set, the individual 322734a1e9eSPaolo Bonzini // routing bits for each of the timers are used. 323734a1e9eSPaolo Bonzini self.get_individual_route() 324734a1e9eSPaolo Bonzini } 325734a1e9eSPaolo Bonzini } 326734a1e9eSPaolo Bonzini 327734a1e9eSPaolo Bonzini fn set_irq(&mut self, set: bool) { 328734a1e9eSPaolo Bonzini let route = self.get_int_route(); 329734a1e9eSPaolo Bonzini 330734a1e9eSPaolo Bonzini if set && self.is_int_enabled() && self.get_state().is_hpet_enabled() { 331734a1e9eSPaolo Bonzini if self.is_fsb_route_enabled() { 332734a1e9eSPaolo Bonzini // SAFETY: 333734a1e9eSPaolo Bonzini // the parameters are valid. 334734a1e9eSPaolo Bonzini unsafe { 335734a1e9eSPaolo Bonzini address_space_stl_le( 336734a1e9eSPaolo Bonzini addr_of_mut!(address_space_memory), 337734a1e9eSPaolo Bonzini self.fsb >> 32, // Timer N FSB int addr 338734a1e9eSPaolo Bonzini self.fsb as u32, // Timer N FSB int value, truncate! 339734a1e9eSPaolo Bonzini MEMTXATTRS_UNSPECIFIED, 340734a1e9eSPaolo Bonzini null_mut(), 341734a1e9eSPaolo Bonzini ); 342734a1e9eSPaolo Bonzini } 343734a1e9eSPaolo Bonzini } else if self.is_int_level_triggered() { 344734a1e9eSPaolo Bonzini self.get_state().irqs[route].raise(); 345734a1e9eSPaolo Bonzini } else { 346734a1e9eSPaolo Bonzini self.get_state().irqs[route].pulse(); 347734a1e9eSPaolo Bonzini } 348734a1e9eSPaolo Bonzini } else if !self.is_fsb_route_enabled() { 349734a1e9eSPaolo Bonzini self.get_state().irqs[route].lower(); 350734a1e9eSPaolo Bonzini } 351734a1e9eSPaolo Bonzini } 352734a1e9eSPaolo Bonzini 353734a1e9eSPaolo Bonzini fn update_irq(&mut self, set: bool) { 354734a1e9eSPaolo Bonzini // If Timer N Interrupt Enable bit is 0, "the timer will 355734a1e9eSPaolo Bonzini // still operate and generate appropriate status bits, but 356734a1e9eSPaolo Bonzini // will not cause an interrupt" 357734a1e9eSPaolo Bonzini self.get_state() 358734a1e9eSPaolo Bonzini .update_int_status(self.index.into(), set && self.is_int_level_triggered()); 359734a1e9eSPaolo Bonzini self.set_irq(set); 360734a1e9eSPaolo Bonzini } 361734a1e9eSPaolo Bonzini 362734a1e9eSPaolo Bonzini fn arm_timer(&mut self, tick: u64) { 363734a1e9eSPaolo Bonzini let mut ns = self.get_state().get_ns(tick); 364734a1e9eSPaolo Bonzini 365734a1e9eSPaolo Bonzini // Clamp period to reasonable min value (1 us) 366734a1e9eSPaolo Bonzini if self.is_periodic() && ns - self.last < 1000 { 367734a1e9eSPaolo Bonzini ns = self.last + 1000; 368734a1e9eSPaolo Bonzini } 369734a1e9eSPaolo Bonzini 370734a1e9eSPaolo Bonzini self.last = ns; 371734a1e9eSPaolo Bonzini self.qemu_timer.modify(self.last); 372734a1e9eSPaolo Bonzini } 373734a1e9eSPaolo Bonzini 374734a1e9eSPaolo Bonzini fn set_timer(&mut self) { 375734a1e9eSPaolo Bonzini let cur_tick: u64 = self.get_state().get_ticks(); 376734a1e9eSPaolo Bonzini 377734a1e9eSPaolo Bonzini self.wrap_flag = 0; 378734a1e9eSPaolo Bonzini self.cmp64 = self.calculate_cmp64(cur_tick, self.cmp); 379734a1e9eSPaolo Bonzini if self.is_32bit_mod() { 380734a1e9eSPaolo Bonzini // HPET spec says in one-shot 32-bit mode, generate an interrupt when 381734a1e9eSPaolo Bonzini // counter wraps in addition to an interrupt with comparator match. 382734a1e9eSPaolo Bonzini if !self.is_periodic() && self.cmp64 > hpet_next_wrap(cur_tick) { 383734a1e9eSPaolo Bonzini self.wrap_flag = 1; 384734a1e9eSPaolo Bonzini self.arm_timer(hpet_next_wrap(cur_tick)); 385734a1e9eSPaolo Bonzini return; 386734a1e9eSPaolo Bonzini } 387734a1e9eSPaolo Bonzini } 388734a1e9eSPaolo Bonzini self.arm_timer(self.cmp64); 389734a1e9eSPaolo Bonzini } 390734a1e9eSPaolo Bonzini 391734a1e9eSPaolo Bonzini fn del_timer(&mut self) { 392734a1e9eSPaolo Bonzini // Just remove the timer from the timer_list without destroying 393734a1e9eSPaolo Bonzini // this timer instance. 394734a1e9eSPaolo Bonzini self.qemu_timer.delete(); 395734a1e9eSPaolo Bonzini 396734a1e9eSPaolo Bonzini if self.is_int_active() { 397734a1e9eSPaolo Bonzini // For level-triggered interrupt, this leaves interrupt status 398734a1e9eSPaolo Bonzini // register set but lowers irq. 399734a1e9eSPaolo Bonzini self.update_irq(true); 400734a1e9eSPaolo Bonzini } 401734a1e9eSPaolo Bonzini } 402734a1e9eSPaolo Bonzini 403734a1e9eSPaolo Bonzini /// Configuration and Capability Register 404734a1e9eSPaolo Bonzini fn set_tn_cfg_reg(&mut self, shift: u32, len: u32, val: u64) { 405734a1e9eSPaolo Bonzini // TODO: Add trace point - trace_hpet_ram_write_tn_cfg(addr & 4) 406734a1e9eSPaolo Bonzini let old_val: u64 = self.config; 407734a1e9eSPaolo Bonzini let mut new_val: u64 = old_val.deposit(shift, len, val); 408734a1e9eSPaolo Bonzini new_val = hpet_fixup_reg(new_val, old_val, HPET_TN_CFG_WRITE_MASK); 409734a1e9eSPaolo Bonzini 410734a1e9eSPaolo Bonzini // Switch level-type interrupt to edge-type. 411734a1e9eSPaolo Bonzini if deactivating_bit(old_val, new_val, HPET_TN_CFG_INT_TYPE_SHIFT) { 412734a1e9eSPaolo Bonzini // Do this before changing timer.config; otherwise, if 413734a1e9eSPaolo Bonzini // HPET_TN_FSB is set, update_irq will not lower the qemu_irq. 414734a1e9eSPaolo Bonzini self.update_irq(false); 415734a1e9eSPaolo Bonzini } 416734a1e9eSPaolo Bonzini 417734a1e9eSPaolo Bonzini self.config = new_val; 418734a1e9eSPaolo Bonzini 419734a1e9eSPaolo Bonzini if activating_bit(old_val, new_val, HPET_TN_CFG_INT_ENABLE_SHIFT) && self.is_int_active() { 420734a1e9eSPaolo Bonzini self.update_irq(true); 421734a1e9eSPaolo Bonzini } 422734a1e9eSPaolo Bonzini 423734a1e9eSPaolo Bonzini if self.is_32bit_mod() { 424734a1e9eSPaolo Bonzini self.cmp = u64::from(self.cmp as u32); // truncate! 425734a1e9eSPaolo Bonzini self.period = u64::from(self.period as u32); // truncate! 426734a1e9eSPaolo Bonzini } 427734a1e9eSPaolo Bonzini 428734a1e9eSPaolo Bonzini if self.get_state().is_hpet_enabled() { 429734a1e9eSPaolo Bonzini self.set_timer(); 430734a1e9eSPaolo Bonzini } 431734a1e9eSPaolo Bonzini } 432734a1e9eSPaolo Bonzini 433734a1e9eSPaolo Bonzini /// Comparator Value Register 434734a1e9eSPaolo Bonzini fn set_tn_cmp_reg(&mut self, shift: u32, len: u32, val: u64) { 435734a1e9eSPaolo Bonzini let mut length = len; 436734a1e9eSPaolo Bonzini let mut value = val; 437734a1e9eSPaolo Bonzini 438734a1e9eSPaolo Bonzini // TODO: Add trace point - trace_hpet_ram_write_tn_cmp(addr & 4) 439734a1e9eSPaolo Bonzini if self.is_32bit_mod() { 440734a1e9eSPaolo Bonzini // High 32-bits are zero, leave them untouched. 441734a1e9eSPaolo Bonzini if shift != 0 { 442734a1e9eSPaolo Bonzini // TODO: Add trace point - trace_hpet_ram_write_invalid_tn_cmp() 443734a1e9eSPaolo Bonzini return; 444734a1e9eSPaolo Bonzini } 445734a1e9eSPaolo Bonzini length = 64; 446734a1e9eSPaolo Bonzini value = u64::from(value as u32); // truncate! 447734a1e9eSPaolo Bonzini } 448734a1e9eSPaolo Bonzini 449734a1e9eSPaolo Bonzini if !self.is_periodic() || self.is_valset_enabled() { 450734a1e9eSPaolo Bonzini self.cmp = self.cmp.deposit(shift, length, value); 451734a1e9eSPaolo Bonzini } 452734a1e9eSPaolo Bonzini 453734a1e9eSPaolo Bonzini if self.is_periodic() { 454734a1e9eSPaolo Bonzini self.period = self.period.deposit(shift, length, value); 455734a1e9eSPaolo Bonzini } 456734a1e9eSPaolo Bonzini 457734a1e9eSPaolo Bonzini self.clear_valset(); 458734a1e9eSPaolo Bonzini if self.get_state().is_hpet_enabled() { 459734a1e9eSPaolo Bonzini self.set_timer(); 460734a1e9eSPaolo Bonzini } 461734a1e9eSPaolo Bonzini } 462734a1e9eSPaolo Bonzini 463734a1e9eSPaolo Bonzini /// FSB Interrupt Route Register 464734a1e9eSPaolo Bonzini fn set_tn_fsb_route_reg(&mut self, shift: u32, len: u32, val: u64) { 465734a1e9eSPaolo Bonzini self.fsb = self.fsb.deposit(shift, len, val); 466734a1e9eSPaolo Bonzini } 467734a1e9eSPaolo Bonzini 468734a1e9eSPaolo Bonzini fn reset(&mut self) { 469734a1e9eSPaolo Bonzini self.del_timer(); 470734a1e9eSPaolo Bonzini self.cmp = u64::MAX; // Comparator Match Registers reset to all 1's. 471734a1e9eSPaolo Bonzini self.config = (1 << HPET_TN_CFG_PERIODIC_CAP_SHIFT) | (1 << HPET_TN_CFG_SIZE_CAP_SHIFT); 472734a1e9eSPaolo Bonzini if self.get_state().has_msi_flag() { 473734a1e9eSPaolo Bonzini self.config |= 1 << HPET_TN_CFG_FSB_CAP_SHIFT; 474734a1e9eSPaolo Bonzini } 475734a1e9eSPaolo Bonzini // advertise availability of ioapic int 476734a1e9eSPaolo Bonzini self.config |= 477734a1e9eSPaolo Bonzini (u64::from(self.get_state().int_route_cap)) << HPET_TN_CFG_INT_ROUTE_CAP_SHIFT; 478734a1e9eSPaolo Bonzini self.period = 0; 479734a1e9eSPaolo Bonzini self.wrap_flag = 0; 480734a1e9eSPaolo Bonzini } 481734a1e9eSPaolo Bonzini 482734a1e9eSPaolo Bonzini /// timer expiration callback 483734a1e9eSPaolo Bonzini fn callback(&mut self) { 484734a1e9eSPaolo Bonzini let period: u64 = self.period; 485734a1e9eSPaolo Bonzini let cur_tick: u64 = self.get_state().get_ticks(); 486734a1e9eSPaolo Bonzini 487734a1e9eSPaolo Bonzini if self.is_periodic() && period != 0 { 488734a1e9eSPaolo Bonzini while hpet_time_after(cur_tick, self.cmp64) { 489734a1e9eSPaolo Bonzini self.cmp64 += period; 490734a1e9eSPaolo Bonzini } 491734a1e9eSPaolo Bonzini if self.is_32bit_mod() { 492734a1e9eSPaolo Bonzini self.cmp = u64::from(self.cmp64 as u32); // truncate! 493734a1e9eSPaolo Bonzini } else { 494734a1e9eSPaolo Bonzini self.cmp = self.cmp64; 495734a1e9eSPaolo Bonzini } 496734a1e9eSPaolo Bonzini self.arm_timer(self.cmp64); 497734a1e9eSPaolo Bonzini } else if self.wrap_flag != 0 { 498734a1e9eSPaolo Bonzini self.wrap_flag = 0; 499734a1e9eSPaolo Bonzini self.arm_timer(self.cmp64); 500734a1e9eSPaolo Bonzini } 501734a1e9eSPaolo Bonzini self.update_irq(true); 502734a1e9eSPaolo Bonzini } 503734a1e9eSPaolo Bonzini 504734a1e9eSPaolo Bonzini const fn read(&self, reg: TimerRegister) -> u64 { 505734a1e9eSPaolo Bonzini use TimerRegister::*; 506734a1e9eSPaolo Bonzini match reg { 507734a1e9eSPaolo Bonzini CFG => self.config, // including interrupt capabilities 508734a1e9eSPaolo Bonzini CMP => self.cmp, // comparator register 509734a1e9eSPaolo Bonzini ROUTE => self.fsb, 510734a1e9eSPaolo Bonzini } 511734a1e9eSPaolo Bonzini } 512734a1e9eSPaolo Bonzini 513734a1e9eSPaolo Bonzini fn write(&mut self, reg: TimerRegister, value: u64, shift: u32, len: u32) { 514734a1e9eSPaolo Bonzini use TimerRegister::*; 515734a1e9eSPaolo Bonzini match reg { 516734a1e9eSPaolo Bonzini CFG => self.set_tn_cfg_reg(shift, len, value), 517734a1e9eSPaolo Bonzini CMP => self.set_tn_cmp_reg(shift, len, value), 518734a1e9eSPaolo Bonzini ROUTE => self.set_tn_fsb_route_reg(shift, len, value), 519734a1e9eSPaolo Bonzini } 520734a1e9eSPaolo Bonzini } 521734a1e9eSPaolo Bonzini } 522734a1e9eSPaolo Bonzini 523734a1e9eSPaolo Bonzini /// HPET Event Timer Block Abstraction 524734a1e9eSPaolo Bonzini #[repr(C)] 525734a1e9eSPaolo Bonzini #[derive(qemu_api_macros::Object)] 526734a1e9eSPaolo Bonzini pub struct HPETState { 527734a1e9eSPaolo Bonzini parent_obj: ParentField<SysBusDevice>, 528734a1e9eSPaolo Bonzini iomem: MemoryRegion, 529734a1e9eSPaolo Bonzini 530734a1e9eSPaolo Bonzini // HPET block Registers: Memory-mapped, software visible registers 531734a1e9eSPaolo Bonzini /// General Capabilities and ID Register 532734a1e9eSPaolo Bonzini capability: BqlCell<u64>, 533734a1e9eSPaolo Bonzini /// General Configuration Register 534734a1e9eSPaolo Bonzini config: BqlCell<u64>, 535734a1e9eSPaolo Bonzini /// General Interrupt Status Register 536734a1e9eSPaolo Bonzini #[doc(alias = "isr")] 537734a1e9eSPaolo Bonzini int_status: BqlCell<u64>, 538734a1e9eSPaolo Bonzini /// Main Counter Value Register 539734a1e9eSPaolo Bonzini #[doc(alias = "hpet_counter")] 540734a1e9eSPaolo Bonzini counter: BqlCell<u64>, 541734a1e9eSPaolo Bonzini 542734a1e9eSPaolo Bonzini // Internal state 543734a1e9eSPaolo Bonzini /// Capabilities that QEMU HPET supports. 544734a1e9eSPaolo Bonzini /// bit 0: MSI (or FSB) support. 545734a1e9eSPaolo Bonzini flags: u32, 546734a1e9eSPaolo Bonzini 547734a1e9eSPaolo Bonzini /// Offset of main counter relative to qemu clock. 548734a1e9eSPaolo Bonzini hpet_offset: BqlCell<u64>, 549734a1e9eSPaolo Bonzini hpet_offset_saved: bool, 550734a1e9eSPaolo Bonzini 551734a1e9eSPaolo Bonzini irqs: [InterruptSource; HPET_NUM_IRQ_ROUTES], 552734a1e9eSPaolo Bonzini rtc_irq_level: BqlCell<u32>, 553734a1e9eSPaolo Bonzini pit_enabled: InterruptSource, 554734a1e9eSPaolo Bonzini 555734a1e9eSPaolo Bonzini /// Interrupt Routing Capability. 556734a1e9eSPaolo Bonzini /// This field indicates to which interrupts in the I/O (x) APIC 557734a1e9eSPaolo Bonzini /// the timers' interrupt can be routed, and is encoded in the 558734a1e9eSPaolo Bonzini /// bits 32:64 of timer N's config register: 559734a1e9eSPaolo Bonzini #[doc(alias = "intcap")] 560734a1e9eSPaolo Bonzini int_route_cap: u32, 561734a1e9eSPaolo Bonzini 562734a1e9eSPaolo Bonzini /// HPET timer array managed by this timer block. 563734a1e9eSPaolo Bonzini #[doc(alias = "timer")] 564b3bf86b8SPaolo Bonzini timers: [BqlRefCell<HPETTimer>; HPET_MAX_TIMERS], 565*869b0afaSZhao Liu num_timers: usize, 566734a1e9eSPaolo Bonzini num_timers_save: BqlCell<u8>, 567734a1e9eSPaolo Bonzini 568734a1e9eSPaolo Bonzini /// Instance id (HPET timer block ID). 569734a1e9eSPaolo Bonzini hpet_id: BqlCell<usize>, 570734a1e9eSPaolo Bonzini } 571734a1e9eSPaolo Bonzini 572734a1e9eSPaolo Bonzini impl HPETState { 573734a1e9eSPaolo Bonzini const fn has_msi_flag(&self) -> bool { 574734a1e9eSPaolo Bonzini self.flags & (1 << HPET_FLAG_MSI_SUPPORT_SHIFT) != 0 575734a1e9eSPaolo Bonzini } 576734a1e9eSPaolo Bonzini 577734a1e9eSPaolo Bonzini fn is_legacy_mode(&self) -> bool { 578734a1e9eSPaolo Bonzini self.config.get() & (1 << HPET_CFG_LEG_RT_SHIFT) != 0 579734a1e9eSPaolo Bonzini } 580734a1e9eSPaolo Bonzini 581734a1e9eSPaolo Bonzini fn is_hpet_enabled(&self) -> bool { 582734a1e9eSPaolo Bonzini self.config.get() & (1 << HPET_CFG_ENABLE_SHIFT) != 0 583734a1e9eSPaolo Bonzini } 584734a1e9eSPaolo Bonzini 585734a1e9eSPaolo Bonzini fn is_timer_int_active(&self, index: usize) -> bool { 586734a1e9eSPaolo Bonzini self.int_status.get() & (1 << index) != 0 587734a1e9eSPaolo Bonzini } 588734a1e9eSPaolo Bonzini 589734a1e9eSPaolo Bonzini fn get_ticks(&self) -> u64 { 590734a1e9eSPaolo Bonzini ns_to_ticks(CLOCK_VIRTUAL.get_ns() + self.hpet_offset.get()) 591734a1e9eSPaolo Bonzini } 592734a1e9eSPaolo Bonzini 593734a1e9eSPaolo Bonzini fn get_ns(&self, tick: u64) -> u64 { 594734a1e9eSPaolo Bonzini ticks_to_ns(tick) - self.hpet_offset.get() 595734a1e9eSPaolo Bonzini } 596734a1e9eSPaolo Bonzini 597734a1e9eSPaolo Bonzini fn handle_legacy_irq(&self, irq: u32, level: u32) { 598734a1e9eSPaolo Bonzini if irq == HPET_LEGACY_PIT_INT { 599734a1e9eSPaolo Bonzini if !self.is_legacy_mode() { 600734a1e9eSPaolo Bonzini self.irqs[0].set(level != 0); 601734a1e9eSPaolo Bonzini } 602734a1e9eSPaolo Bonzini } else { 603734a1e9eSPaolo Bonzini self.rtc_irq_level.set(level); 604734a1e9eSPaolo Bonzini if !self.is_legacy_mode() { 605734a1e9eSPaolo Bonzini self.irqs[RTC_ISA_IRQ].set(level != 0); 606734a1e9eSPaolo Bonzini } 607734a1e9eSPaolo Bonzini } 608734a1e9eSPaolo Bonzini } 609734a1e9eSPaolo Bonzini 610734a1e9eSPaolo Bonzini fn init_timer(&self) { 611734a1e9eSPaolo Bonzini for (index, timer) in self.timers.iter().enumerate() { 612734a1e9eSPaolo Bonzini timer.borrow_mut().init(index.try_into().unwrap(), self); 613734a1e9eSPaolo Bonzini } 614734a1e9eSPaolo Bonzini } 615734a1e9eSPaolo Bonzini 616734a1e9eSPaolo Bonzini fn update_int_status(&self, index: u32, level: bool) { 617734a1e9eSPaolo Bonzini self.int_status 618734a1e9eSPaolo Bonzini .set(self.int_status.get().deposit(index, 1, u64::from(level))); 619734a1e9eSPaolo Bonzini } 620734a1e9eSPaolo Bonzini 621734a1e9eSPaolo Bonzini /// General Configuration Register 622734a1e9eSPaolo Bonzini fn set_cfg_reg(&self, shift: u32, len: u32, val: u64) { 623734a1e9eSPaolo Bonzini let old_val = self.config.get(); 624734a1e9eSPaolo Bonzini let mut new_val = old_val.deposit(shift, len, val); 625734a1e9eSPaolo Bonzini 626734a1e9eSPaolo Bonzini new_val = hpet_fixup_reg(new_val, old_val, HPET_CFG_WRITE_MASK); 627734a1e9eSPaolo Bonzini self.config.set(new_val); 628734a1e9eSPaolo Bonzini 629734a1e9eSPaolo Bonzini if activating_bit(old_val, new_val, HPET_CFG_ENABLE_SHIFT) { 630734a1e9eSPaolo Bonzini // Enable main counter and interrupt generation. 631734a1e9eSPaolo Bonzini self.hpet_offset 632734a1e9eSPaolo Bonzini .set(ticks_to_ns(self.counter.get()) - CLOCK_VIRTUAL.get_ns()); 633734a1e9eSPaolo Bonzini 634*869b0afaSZhao Liu for timer in self.timers.iter().take(self.num_timers) { 635734a1e9eSPaolo Bonzini let mut t = timer.borrow_mut(); 636734a1e9eSPaolo Bonzini 637734a1e9eSPaolo Bonzini if t.is_int_enabled() && t.is_int_active() { 638734a1e9eSPaolo Bonzini t.update_irq(true); 639734a1e9eSPaolo Bonzini } 640734a1e9eSPaolo Bonzini t.set_timer(); 641734a1e9eSPaolo Bonzini } 642734a1e9eSPaolo Bonzini } else if deactivating_bit(old_val, new_val, HPET_CFG_ENABLE_SHIFT) { 643734a1e9eSPaolo Bonzini // Halt main counter and disable interrupt generation. 644734a1e9eSPaolo Bonzini self.counter.set(self.get_ticks()); 645734a1e9eSPaolo Bonzini 646*869b0afaSZhao Liu for timer in self.timers.iter().take(self.num_timers) { 647734a1e9eSPaolo Bonzini timer.borrow_mut().del_timer(); 648734a1e9eSPaolo Bonzini } 649734a1e9eSPaolo Bonzini } 650734a1e9eSPaolo Bonzini 651734a1e9eSPaolo Bonzini // i8254 and RTC output pins are disabled when HPET is in legacy mode 652734a1e9eSPaolo Bonzini if activating_bit(old_val, new_val, HPET_CFG_LEG_RT_SHIFT) { 653734a1e9eSPaolo Bonzini self.pit_enabled.set(false); 654734a1e9eSPaolo Bonzini self.irqs[0].lower(); 655734a1e9eSPaolo Bonzini self.irqs[RTC_ISA_IRQ].lower(); 656734a1e9eSPaolo Bonzini } else if deactivating_bit(old_val, new_val, HPET_CFG_LEG_RT_SHIFT) { 657734a1e9eSPaolo Bonzini // TODO: Add irq binding: qemu_irq_lower(s->irqs[0]) 658734a1e9eSPaolo Bonzini self.irqs[0].lower(); 659734a1e9eSPaolo Bonzini self.pit_enabled.set(true); 660734a1e9eSPaolo Bonzini self.irqs[RTC_ISA_IRQ].set(self.rtc_irq_level.get() != 0); 661734a1e9eSPaolo Bonzini } 662734a1e9eSPaolo Bonzini } 663734a1e9eSPaolo Bonzini 664734a1e9eSPaolo Bonzini /// General Interrupt Status Register: Read/Write Clear 665734a1e9eSPaolo Bonzini fn set_int_status_reg(&self, shift: u32, _len: u32, val: u64) { 666734a1e9eSPaolo Bonzini let new_val = val << shift; 667734a1e9eSPaolo Bonzini let cleared = new_val & self.int_status.get(); 668734a1e9eSPaolo Bonzini 669*869b0afaSZhao Liu for (index, timer) in self.timers.iter().take(self.num_timers).enumerate() { 670734a1e9eSPaolo Bonzini if cleared & (1 << index) != 0 { 671734a1e9eSPaolo Bonzini timer.borrow_mut().update_irq(false); 672734a1e9eSPaolo Bonzini } 673734a1e9eSPaolo Bonzini } 674734a1e9eSPaolo Bonzini } 675734a1e9eSPaolo Bonzini 676734a1e9eSPaolo Bonzini /// Main Counter Value Register 677734a1e9eSPaolo Bonzini fn set_counter_reg(&self, shift: u32, len: u32, val: u64) { 678734a1e9eSPaolo Bonzini if self.is_hpet_enabled() { 679734a1e9eSPaolo Bonzini // TODO: Add trace point - 680734a1e9eSPaolo Bonzini // trace_hpet_ram_write_counter_write_while_enabled() 681734a1e9eSPaolo Bonzini // 682734a1e9eSPaolo Bonzini // HPET spec says that writes to this register should only be 683734a1e9eSPaolo Bonzini // done while the counter is halted. So this is an undefined 684734a1e9eSPaolo Bonzini // behavior. There's no need to forbid it, but when HPET is 685734a1e9eSPaolo Bonzini // enabled, the changed counter value will not affect the 686734a1e9eSPaolo Bonzini // tick count (i.e., the previously calculated offset will 687734a1e9eSPaolo Bonzini // not be changed as well). 688734a1e9eSPaolo Bonzini } 689734a1e9eSPaolo Bonzini self.counter 690734a1e9eSPaolo Bonzini .set(self.counter.get().deposit(shift, len, val)); 691734a1e9eSPaolo Bonzini } 692734a1e9eSPaolo Bonzini 693734a1e9eSPaolo Bonzini unsafe fn init(&mut self) { 694734a1e9eSPaolo Bonzini static HPET_RAM_OPS: MemoryRegionOps<HPETState> = 695734a1e9eSPaolo Bonzini MemoryRegionOpsBuilder::<HPETState>::new() 696734a1e9eSPaolo Bonzini .read(&HPETState::read) 697734a1e9eSPaolo Bonzini .write(&HPETState::write) 698734a1e9eSPaolo Bonzini .native_endian() 699734a1e9eSPaolo Bonzini .valid_sizes(4, 8) 700734a1e9eSPaolo Bonzini .impl_sizes(4, 8) 701734a1e9eSPaolo Bonzini .build(); 702734a1e9eSPaolo Bonzini 703734a1e9eSPaolo Bonzini // SAFETY: 704734a1e9eSPaolo Bonzini // self and self.iomem are guaranteed to be valid at this point since callers 705734a1e9eSPaolo Bonzini // must make sure the `self` reference is valid. 706734a1e9eSPaolo Bonzini MemoryRegion::init_io( 707734a1e9eSPaolo Bonzini unsafe { &mut *addr_of_mut!(self.iomem) }, 708734a1e9eSPaolo Bonzini addr_of_mut!(*self), 709734a1e9eSPaolo Bonzini &HPET_RAM_OPS, 710734a1e9eSPaolo Bonzini "hpet", 711734a1e9eSPaolo Bonzini HPET_REG_SPACE_LEN, 712734a1e9eSPaolo Bonzini ); 713734a1e9eSPaolo Bonzini } 714734a1e9eSPaolo Bonzini 715734a1e9eSPaolo Bonzini fn post_init(&self) { 716734a1e9eSPaolo Bonzini self.init_mmio(&self.iomem); 717734a1e9eSPaolo Bonzini for irq in self.irqs.iter() { 718734a1e9eSPaolo Bonzini self.init_irq(irq); 719734a1e9eSPaolo Bonzini } 720734a1e9eSPaolo Bonzini } 721734a1e9eSPaolo Bonzini 7224b66abeaSPaolo Bonzini fn realize(&self) -> qemu_api::Result<()> { 723*869b0afaSZhao Liu if self.num_timers < HPET_MIN_TIMERS || self.num_timers > HPET_MAX_TIMERS { 7244d2fec89SPaolo Bonzini Err(format!( 7254d2fec89SPaolo Bonzini "hpet.num_timers must be between {HPET_MIN_TIMERS} and {HPET_MAX_TIMERS}" 7264d2fec89SPaolo Bonzini ))?; 7274d2fec89SPaolo Bonzini } 728734a1e9eSPaolo Bonzini if self.int_route_cap == 0 { 7294d2fec89SPaolo Bonzini Err("hpet.hpet-intcap property not initialized")?; 730734a1e9eSPaolo Bonzini } 731734a1e9eSPaolo Bonzini 7324d2fec89SPaolo Bonzini self.hpet_id.set(HPETFwConfig::assign_hpet_id()?); 733734a1e9eSPaolo Bonzini 734734a1e9eSPaolo Bonzini self.init_timer(); 735734a1e9eSPaolo Bonzini // 64-bit General Capabilities and ID Register; LegacyReplacementRoute. 736734a1e9eSPaolo Bonzini self.capability.set( 737734a1e9eSPaolo Bonzini HPET_CAP_REV_ID_VALUE << HPET_CAP_REV_ID_SHIFT | 738734a1e9eSPaolo Bonzini 1 << HPET_CAP_COUNT_SIZE_CAP_SHIFT | 739734a1e9eSPaolo Bonzini 1 << HPET_CAP_LEG_RT_CAP_SHIFT | 740734a1e9eSPaolo Bonzini HPET_CAP_VENDER_ID_VALUE << HPET_CAP_VENDER_ID_SHIFT | 741*869b0afaSZhao Liu ((self.num_timers - 1) as u64) << HPET_CAP_NUM_TIM_SHIFT | // indicate the last timer 742734a1e9eSPaolo Bonzini (HPET_CLK_PERIOD * FS_PER_NS) << HPET_CAP_CNT_CLK_PERIOD_SHIFT, // 10 ns 743734a1e9eSPaolo Bonzini ); 744734a1e9eSPaolo Bonzini 745734a1e9eSPaolo Bonzini self.init_gpio_in(2, HPETState::handle_legacy_irq); 746734a1e9eSPaolo Bonzini self.init_gpio_out(from_ref(&self.pit_enabled)); 7474b66abeaSPaolo Bonzini Ok(()) 748734a1e9eSPaolo Bonzini } 749734a1e9eSPaolo Bonzini 750734a1e9eSPaolo Bonzini fn reset_hold(&self, _type: ResetType) { 751*869b0afaSZhao Liu for timer in self.timers.iter().take(self.num_timers) { 752734a1e9eSPaolo Bonzini timer.borrow_mut().reset(); 753734a1e9eSPaolo Bonzini } 754734a1e9eSPaolo Bonzini 755734a1e9eSPaolo Bonzini self.counter.set(0); 756734a1e9eSPaolo Bonzini self.config.set(0); 757734a1e9eSPaolo Bonzini self.pit_enabled.set(true); 758734a1e9eSPaolo Bonzini self.hpet_offset.set(0); 759734a1e9eSPaolo Bonzini 760734a1e9eSPaolo Bonzini HPETFwConfig::update_hpet_cfg( 761734a1e9eSPaolo Bonzini self.hpet_id.get(), 762734a1e9eSPaolo Bonzini self.capability.get() as u32, 763734a1e9eSPaolo Bonzini self.mmio_addr(0).unwrap(), 764734a1e9eSPaolo Bonzini ); 765734a1e9eSPaolo Bonzini 766734a1e9eSPaolo Bonzini // to document that the RTC lowers its output on reset as well 767734a1e9eSPaolo Bonzini self.rtc_irq_level.set(0); 768734a1e9eSPaolo Bonzini } 769734a1e9eSPaolo Bonzini 770734a1e9eSPaolo Bonzini fn decode(&self, mut addr: hwaddr, size: u32) -> HPETAddrDecode { 771734a1e9eSPaolo Bonzini let shift = ((addr & 4) * 8) as u32; 772734a1e9eSPaolo Bonzini let len = std::cmp::min(size * 8, 64 - shift); 773734a1e9eSPaolo Bonzini 774734a1e9eSPaolo Bonzini addr &= !4; 775734a1e9eSPaolo Bonzini let reg = if (0..=0xff).contains(&addr) { 776734a1e9eSPaolo Bonzini GlobalRegister::try_from(addr).map(HPETRegister::Global) 777734a1e9eSPaolo Bonzini } else { 778734a1e9eSPaolo Bonzini let timer_id: usize = ((addr - 0x100) / 0x20) as usize; 779*869b0afaSZhao Liu if timer_id < self.num_timers { 780734a1e9eSPaolo Bonzini // TODO: Add trace point - trace_hpet_ram_[read|write]_timer_id(timer_id) 781734a1e9eSPaolo Bonzini TimerRegister::try_from(addr & 0x18) 782734a1e9eSPaolo Bonzini .map(|reg| HPETRegister::Timer(&self.timers[timer_id], reg)) 783734a1e9eSPaolo Bonzini } else { 784734a1e9eSPaolo Bonzini // TODO: Add trace point - trace_hpet_timer_id_out_of_range(timer_id) 785734a1e9eSPaolo Bonzini Err(addr) 786734a1e9eSPaolo Bonzini } 787734a1e9eSPaolo Bonzini }; 788734a1e9eSPaolo Bonzini 789734a1e9eSPaolo Bonzini // reg is now a Result<HPETRegister, hwaddr> 790734a1e9eSPaolo Bonzini // convert the Err case into HPETRegister as well 791734a1e9eSPaolo Bonzini let reg = reg.unwrap_or_else(HPETRegister::Unknown); 792734a1e9eSPaolo Bonzini HPETAddrDecode { shift, len, reg } 793734a1e9eSPaolo Bonzini } 794734a1e9eSPaolo Bonzini 795734a1e9eSPaolo Bonzini fn read(&self, addr: hwaddr, size: u32) -> u64 { 796734a1e9eSPaolo Bonzini // TODO: Add trace point - trace_hpet_ram_read(addr) 797734a1e9eSPaolo Bonzini let HPETAddrDecode { shift, reg, .. } = self.decode(addr, size); 798734a1e9eSPaolo Bonzini 799734a1e9eSPaolo Bonzini use GlobalRegister::*; 800734a1e9eSPaolo Bonzini use HPETRegister::*; 801734a1e9eSPaolo Bonzini (match reg { 802734a1e9eSPaolo Bonzini Timer(timer, tn_reg) => timer.borrow_mut().read(tn_reg), 803734a1e9eSPaolo Bonzini Global(CAP) => self.capability.get(), /* including HPET_PERIOD 0x004 */ 804734a1e9eSPaolo Bonzini Global(CFG) => self.config.get(), 805734a1e9eSPaolo Bonzini Global(INT_STATUS) => self.int_status.get(), 806734a1e9eSPaolo Bonzini Global(COUNTER) => { 807734a1e9eSPaolo Bonzini // TODO: Add trace point 808734a1e9eSPaolo Bonzini // trace_hpet_ram_read_reading_counter(addr & 4, cur_tick) 809734a1e9eSPaolo Bonzini if self.is_hpet_enabled() { 810734a1e9eSPaolo Bonzini self.get_ticks() 811734a1e9eSPaolo Bonzini } else { 812734a1e9eSPaolo Bonzini self.counter.get() 813734a1e9eSPaolo Bonzini } 814734a1e9eSPaolo Bonzini } 815734a1e9eSPaolo Bonzini Unknown(_) => { 816734a1e9eSPaolo Bonzini // TODO: Add trace point- trace_hpet_ram_read_invalid() 817734a1e9eSPaolo Bonzini 0 818734a1e9eSPaolo Bonzini } 819734a1e9eSPaolo Bonzini }) >> shift 820734a1e9eSPaolo Bonzini } 821734a1e9eSPaolo Bonzini 822734a1e9eSPaolo Bonzini fn write(&self, addr: hwaddr, value: u64, size: u32) { 823734a1e9eSPaolo Bonzini let HPETAddrDecode { shift, len, reg } = self.decode(addr, size); 824734a1e9eSPaolo Bonzini 825734a1e9eSPaolo Bonzini // TODO: Add trace point - trace_hpet_ram_write(addr, value) 826734a1e9eSPaolo Bonzini use GlobalRegister::*; 827734a1e9eSPaolo Bonzini use HPETRegister::*; 828734a1e9eSPaolo Bonzini match reg { 829734a1e9eSPaolo Bonzini Timer(timer, tn_reg) => timer.borrow_mut().write(tn_reg, value, shift, len), 830734a1e9eSPaolo Bonzini Global(CAP) => {} // General Capabilities and ID Register: Read Only 831734a1e9eSPaolo Bonzini Global(CFG) => self.set_cfg_reg(shift, len, value), 832734a1e9eSPaolo Bonzini Global(INT_STATUS) => self.set_int_status_reg(shift, len, value), 833734a1e9eSPaolo Bonzini Global(COUNTER) => self.set_counter_reg(shift, len, value), 834734a1e9eSPaolo Bonzini Unknown(_) => { 835734a1e9eSPaolo Bonzini // TODO: Add trace point - trace_hpet_ram_write_invalid() 836734a1e9eSPaolo Bonzini } 837734a1e9eSPaolo Bonzini } 838734a1e9eSPaolo Bonzini } 839734a1e9eSPaolo Bonzini 840734a1e9eSPaolo Bonzini fn pre_save(&self) -> i32 { 841734a1e9eSPaolo Bonzini if self.is_hpet_enabled() { 842734a1e9eSPaolo Bonzini self.counter.set(self.get_ticks()); 843734a1e9eSPaolo Bonzini } 844734a1e9eSPaolo Bonzini 845734a1e9eSPaolo Bonzini /* 846734a1e9eSPaolo Bonzini * The number of timers must match on source and destination, but it was 847734a1e9eSPaolo Bonzini * also added to the migration stream. Check that it matches the value 848734a1e9eSPaolo Bonzini * that was configured. 849734a1e9eSPaolo Bonzini */ 850*869b0afaSZhao Liu self.num_timers_save.set(self.num_timers as u8); 851734a1e9eSPaolo Bonzini 0 852734a1e9eSPaolo Bonzini } 853734a1e9eSPaolo Bonzini 854734a1e9eSPaolo Bonzini fn post_load(&self, _version_id: u8) -> i32 { 855*869b0afaSZhao Liu for timer in self.timers.iter().take(self.num_timers) { 856734a1e9eSPaolo Bonzini let mut t = timer.borrow_mut(); 857734a1e9eSPaolo Bonzini 858734a1e9eSPaolo Bonzini t.cmp64 = t.calculate_cmp64(t.get_state().counter.get(), t.cmp); 859734a1e9eSPaolo Bonzini t.last = CLOCK_VIRTUAL.get_ns() - NANOSECONDS_PER_SECOND; 860734a1e9eSPaolo Bonzini } 861734a1e9eSPaolo Bonzini 862734a1e9eSPaolo Bonzini // Recalculate the offset between the main counter and guest time 863734a1e9eSPaolo Bonzini if !self.hpet_offset_saved { 864734a1e9eSPaolo Bonzini self.hpet_offset 865734a1e9eSPaolo Bonzini .set(ticks_to_ns(self.counter.get()) - CLOCK_VIRTUAL.get_ns()); 866734a1e9eSPaolo Bonzini } 867734a1e9eSPaolo Bonzini 868734a1e9eSPaolo Bonzini 0 869734a1e9eSPaolo Bonzini } 870734a1e9eSPaolo Bonzini 871734a1e9eSPaolo Bonzini fn is_rtc_irq_level_needed(&self) -> bool { 872734a1e9eSPaolo Bonzini self.rtc_irq_level.get() != 0 873734a1e9eSPaolo Bonzini } 874734a1e9eSPaolo Bonzini 875734a1e9eSPaolo Bonzini fn is_offset_needed(&self) -> bool { 876734a1e9eSPaolo Bonzini self.is_hpet_enabled() && self.hpet_offset_saved 877734a1e9eSPaolo Bonzini } 878734a1e9eSPaolo Bonzini 879734a1e9eSPaolo Bonzini fn validate_num_timers(&self, _version_id: u8) -> bool { 880*869b0afaSZhao Liu self.num_timers == self.num_timers_save.get().into() 881734a1e9eSPaolo Bonzini } 882734a1e9eSPaolo Bonzini } 883734a1e9eSPaolo Bonzini 884734a1e9eSPaolo Bonzini qom_isa!(HPETState: SysBusDevice, DeviceState, Object); 885734a1e9eSPaolo Bonzini 886734a1e9eSPaolo Bonzini unsafe impl ObjectType for HPETState { 887734a1e9eSPaolo Bonzini // No need for HPETClass. Just like OBJECT_DECLARE_SIMPLE_TYPE in C. 888734a1e9eSPaolo Bonzini type Class = <SysBusDevice as ObjectType>::Class; 889734a1e9eSPaolo Bonzini const TYPE_NAME: &'static CStr = crate::TYPE_HPET; 890734a1e9eSPaolo Bonzini } 891734a1e9eSPaolo Bonzini 892734a1e9eSPaolo Bonzini impl ObjectImpl for HPETState { 893734a1e9eSPaolo Bonzini type ParentType = SysBusDevice; 894734a1e9eSPaolo Bonzini 895734a1e9eSPaolo Bonzini const INSTANCE_INIT: Option<unsafe fn(&mut Self)> = Some(Self::init); 896734a1e9eSPaolo Bonzini const INSTANCE_POST_INIT: Option<fn(&Self)> = Some(Self::post_init); 897734a1e9eSPaolo Bonzini const CLASS_INIT: fn(&mut Self::Class) = Self::Class::class_init::<Self>; 898734a1e9eSPaolo Bonzini } 899734a1e9eSPaolo Bonzini 900734a1e9eSPaolo Bonzini // TODO: Make these properties user-configurable! 901734a1e9eSPaolo Bonzini qemu_api::declare_properties! { 902734a1e9eSPaolo Bonzini HPET_PROPERTIES, 903734a1e9eSPaolo Bonzini qemu_api::define_property!( 904734a1e9eSPaolo Bonzini c"timers", 905734a1e9eSPaolo Bonzini HPETState, 906734a1e9eSPaolo Bonzini num_timers, 907b3bf86b8SPaolo Bonzini unsafe { &qdev_prop_usize }, 908734a1e9eSPaolo Bonzini u8, 909734a1e9eSPaolo Bonzini default = HPET_MIN_TIMERS 910734a1e9eSPaolo Bonzini ), 911734a1e9eSPaolo Bonzini qemu_api::define_property!( 912734a1e9eSPaolo Bonzini c"msi", 913734a1e9eSPaolo Bonzini HPETState, 914734a1e9eSPaolo Bonzini flags, 915734a1e9eSPaolo Bonzini unsafe { &qdev_prop_bit }, 916734a1e9eSPaolo Bonzini u32, 917734a1e9eSPaolo Bonzini bit = HPET_FLAG_MSI_SUPPORT_SHIFT as u8, 918734a1e9eSPaolo Bonzini default = false, 919734a1e9eSPaolo Bonzini ), 920734a1e9eSPaolo Bonzini qemu_api::define_property!( 921734a1e9eSPaolo Bonzini c"hpet-intcap", 922734a1e9eSPaolo Bonzini HPETState, 923734a1e9eSPaolo Bonzini int_route_cap, 924734a1e9eSPaolo Bonzini unsafe { &qdev_prop_uint32 }, 925734a1e9eSPaolo Bonzini u32, 926734a1e9eSPaolo Bonzini default = 0 927734a1e9eSPaolo Bonzini ), 928734a1e9eSPaolo Bonzini qemu_api::define_property!( 929734a1e9eSPaolo Bonzini c"hpet-offset-saved", 930734a1e9eSPaolo Bonzini HPETState, 931734a1e9eSPaolo Bonzini hpet_offset_saved, 932734a1e9eSPaolo Bonzini unsafe { &qdev_prop_bool }, 933734a1e9eSPaolo Bonzini bool, 934734a1e9eSPaolo Bonzini default = true 935734a1e9eSPaolo Bonzini ), 936734a1e9eSPaolo Bonzini } 937734a1e9eSPaolo Bonzini 938734a1e9eSPaolo Bonzini unsafe extern "C" fn hpet_rtc_irq_level_needed(opaque: *mut c_void) -> bool { 939734a1e9eSPaolo Bonzini // SAFETY: 940734a1e9eSPaolo Bonzini // the pointer is convertible to a reference 941734a1e9eSPaolo Bonzini let state: &HPETState = unsafe { NonNull::new(opaque.cast::<HPETState>()).unwrap().as_ref() }; 942734a1e9eSPaolo Bonzini state.is_rtc_irq_level_needed() 943734a1e9eSPaolo Bonzini } 944734a1e9eSPaolo Bonzini 945734a1e9eSPaolo Bonzini unsafe extern "C" fn hpet_offset_needed(opaque: *mut c_void) -> bool { 946734a1e9eSPaolo Bonzini // SAFETY: 947734a1e9eSPaolo Bonzini // the pointer is convertible to a reference 948734a1e9eSPaolo Bonzini let state: &HPETState = unsafe { NonNull::new(opaque.cast::<HPETState>()).unwrap().as_ref() }; 949734a1e9eSPaolo Bonzini state.is_offset_needed() 950734a1e9eSPaolo Bonzini } 951734a1e9eSPaolo Bonzini 952734a1e9eSPaolo Bonzini unsafe extern "C" fn hpet_pre_save(opaque: *mut c_void) -> c_int { 953734a1e9eSPaolo Bonzini // SAFETY: 954734a1e9eSPaolo Bonzini // the pointer is convertible to a reference 955734a1e9eSPaolo Bonzini let state: &mut HPETState = 956734a1e9eSPaolo Bonzini unsafe { NonNull::new(opaque.cast::<HPETState>()).unwrap().as_mut() }; 957734a1e9eSPaolo Bonzini state.pre_save() as c_int 958734a1e9eSPaolo Bonzini } 959734a1e9eSPaolo Bonzini 960734a1e9eSPaolo Bonzini unsafe extern "C" fn hpet_post_load(opaque: *mut c_void, version_id: c_int) -> c_int { 961734a1e9eSPaolo Bonzini // SAFETY: 962734a1e9eSPaolo Bonzini // the pointer is convertible to a reference 963734a1e9eSPaolo Bonzini let state: &mut HPETState = 964734a1e9eSPaolo Bonzini unsafe { NonNull::new(opaque.cast::<HPETState>()).unwrap().as_mut() }; 965734a1e9eSPaolo Bonzini let version: u8 = version_id.try_into().unwrap(); 966734a1e9eSPaolo Bonzini state.post_load(version) as c_int 967734a1e9eSPaolo Bonzini } 968734a1e9eSPaolo Bonzini 969734a1e9eSPaolo Bonzini static VMSTATE_HPET_RTC_IRQ_LEVEL: VMStateDescription = VMStateDescription { 970734a1e9eSPaolo Bonzini name: c"hpet/rtc_irq_level".as_ptr(), 971734a1e9eSPaolo Bonzini version_id: 1, 972734a1e9eSPaolo Bonzini minimum_version_id: 1, 973734a1e9eSPaolo Bonzini needed: Some(hpet_rtc_irq_level_needed), 974734a1e9eSPaolo Bonzini fields: vmstate_fields! { 975734a1e9eSPaolo Bonzini vmstate_of!(HPETState, rtc_irq_level), 976734a1e9eSPaolo Bonzini }, 977734a1e9eSPaolo Bonzini ..Zeroable::ZERO 978734a1e9eSPaolo Bonzini }; 979734a1e9eSPaolo Bonzini 980734a1e9eSPaolo Bonzini static VMSTATE_HPET_OFFSET: VMStateDescription = VMStateDescription { 981734a1e9eSPaolo Bonzini name: c"hpet/offset".as_ptr(), 982734a1e9eSPaolo Bonzini version_id: 1, 983734a1e9eSPaolo Bonzini minimum_version_id: 1, 984734a1e9eSPaolo Bonzini needed: Some(hpet_offset_needed), 985734a1e9eSPaolo Bonzini fields: vmstate_fields! { 986734a1e9eSPaolo Bonzini vmstate_of!(HPETState, hpet_offset), 987734a1e9eSPaolo Bonzini }, 988734a1e9eSPaolo Bonzini ..Zeroable::ZERO 989734a1e9eSPaolo Bonzini }; 990734a1e9eSPaolo Bonzini 991734a1e9eSPaolo Bonzini static VMSTATE_HPET_TIMER: VMStateDescription = VMStateDescription { 992734a1e9eSPaolo Bonzini name: c"hpet_timer".as_ptr(), 993734a1e9eSPaolo Bonzini version_id: 1, 994734a1e9eSPaolo Bonzini minimum_version_id: 1, 995734a1e9eSPaolo Bonzini fields: vmstate_fields! { 996734a1e9eSPaolo Bonzini vmstate_of!(HPETTimer, index), 997734a1e9eSPaolo Bonzini vmstate_of!(HPETTimer, config), 998734a1e9eSPaolo Bonzini vmstate_of!(HPETTimer, cmp), 999734a1e9eSPaolo Bonzini vmstate_of!(HPETTimer, fsb), 1000734a1e9eSPaolo Bonzini vmstate_of!(HPETTimer, period), 1001734a1e9eSPaolo Bonzini vmstate_of!(HPETTimer, wrap_flag), 1002734a1e9eSPaolo Bonzini vmstate_of!(HPETTimer, qemu_timer), 1003734a1e9eSPaolo Bonzini }, 1004734a1e9eSPaolo Bonzini ..Zeroable::ZERO 1005734a1e9eSPaolo Bonzini }; 1006734a1e9eSPaolo Bonzini 1007734a1e9eSPaolo Bonzini const VALIDATE_TIMERS_NAME: &CStr = c"num_timers must match"; 1008734a1e9eSPaolo Bonzini 1009734a1e9eSPaolo Bonzini static VMSTATE_HPET: VMStateDescription = VMStateDescription { 1010734a1e9eSPaolo Bonzini name: c"hpet".as_ptr(), 1011734a1e9eSPaolo Bonzini version_id: 2, 1012b3bf86b8SPaolo Bonzini minimum_version_id: 2, 1013734a1e9eSPaolo Bonzini pre_save: Some(hpet_pre_save), 1014734a1e9eSPaolo Bonzini post_load: Some(hpet_post_load), 1015734a1e9eSPaolo Bonzini fields: vmstate_fields! { 1016734a1e9eSPaolo Bonzini vmstate_of!(HPETState, config), 1017734a1e9eSPaolo Bonzini vmstate_of!(HPETState, int_status), 1018734a1e9eSPaolo Bonzini vmstate_of!(HPETState, counter), 1019b3bf86b8SPaolo Bonzini vmstate_of!(HPETState, num_timers_save), 1020734a1e9eSPaolo Bonzini vmstate_validate!(HPETState, VALIDATE_TIMERS_NAME, HPETState::validate_num_timers), 1021b3bf86b8SPaolo Bonzini vmstate_struct!(HPETState, timers[0 .. num_timers_save], &VMSTATE_HPET_TIMER, BqlRefCell<HPETTimer>, HPETState::validate_num_timers).with_version_id(0), 1022734a1e9eSPaolo Bonzini }, 1023734a1e9eSPaolo Bonzini subsections: vmstate_subsections! { 1024734a1e9eSPaolo Bonzini VMSTATE_HPET_RTC_IRQ_LEVEL, 1025734a1e9eSPaolo Bonzini VMSTATE_HPET_OFFSET, 1026734a1e9eSPaolo Bonzini }, 1027734a1e9eSPaolo Bonzini ..Zeroable::ZERO 1028734a1e9eSPaolo Bonzini }; 1029734a1e9eSPaolo Bonzini 1030734a1e9eSPaolo Bonzini impl DeviceImpl for HPETState { 1031734a1e9eSPaolo Bonzini fn properties() -> &'static [Property] { 1032734a1e9eSPaolo Bonzini &HPET_PROPERTIES 1033734a1e9eSPaolo Bonzini } 1034734a1e9eSPaolo Bonzini 1035734a1e9eSPaolo Bonzini fn vmsd() -> Option<&'static VMStateDescription> { 1036734a1e9eSPaolo Bonzini Some(&VMSTATE_HPET) 1037734a1e9eSPaolo Bonzini } 1038734a1e9eSPaolo Bonzini 10394b66abeaSPaolo Bonzini const REALIZE: Option<fn(&Self) -> qemu_api::Result<()>> = Some(Self::realize); 1040734a1e9eSPaolo Bonzini } 1041734a1e9eSPaolo Bonzini 1042734a1e9eSPaolo Bonzini impl ResettablePhasesImpl for HPETState { 1043734a1e9eSPaolo Bonzini const HOLD: Option<fn(&Self, ResetType)> = Some(Self::reset_hold); 1044734a1e9eSPaolo Bonzini } 1045734a1e9eSPaolo Bonzini 1046734a1e9eSPaolo Bonzini impl SysBusDeviceImpl for HPETState {} 1047