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