1 // Copyright (C) 2024 Intel Corporation. 2 // Author(s): Zhao Liu <zhao1.liu@intel.com> 3 // SPDX-License-Identifier: GPL-2.0-or-later 4 5 use std::ptr::addr_of_mut; 6 7 use qemu_api::{cell::bql_locked, zeroable::Zeroable}; 8 9 /// Each `HPETState` represents a Event Timer Block. The v1 spec supports 10 /// up to 8 blocks. QEMU only uses 1 block (in PC machine). 11 const HPET_MAX_NUM_EVENT_TIMER_BLOCK: usize = 8; 12 13 #[repr(C, packed)] 14 #[derive(Copy, Clone, Default)] 15 pub struct HPETFwEntry { 16 pub event_timer_block_id: u32, 17 pub address: u64, 18 pub min_tick: u16, 19 pub page_prot: u8, 20 } 21 unsafe impl Zeroable for HPETFwEntry {} 22 23 #[repr(C, packed)] 24 #[derive(Copy, Clone, Default)] 25 pub struct HPETFwConfig { 26 pub count: u8, 27 pub hpet: [HPETFwEntry; HPET_MAX_NUM_EVENT_TIMER_BLOCK], 28 } 29 unsafe impl Zeroable for HPETFwConfig {} 30 31 #[allow(non_upper_case_globals)] 32 #[no_mangle] 33 pub static mut hpet_fw_cfg: HPETFwConfig = HPETFwConfig { 34 count: u8::MAX, 35 ..Zeroable::ZERO 36 }; 37 38 impl HPETFwConfig { assign_hpet_id() -> Result<usize, &'static str>39 pub(crate) fn assign_hpet_id() -> Result<usize, &'static str> { 40 assert!(bql_locked()); 41 // SAFETY: all accesses go through these methods, which guarantee 42 // that the accesses are protected by the BQL. 43 let mut fw_cfg = unsafe { *addr_of_mut!(hpet_fw_cfg) }; 44 45 if fw_cfg.count == u8::MAX { 46 // first instance 47 fw_cfg.count = 0; 48 } 49 50 if fw_cfg.count == 8 { 51 Err("Only 8 instances of HPET are allowed")?; 52 } 53 54 let id: usize = fw_cfg.count.into(); 55 fw_cfg.count += 1; 56 Ok(id) 57 } 58 update_hpet_cfg(hpet_id: usize, timer_block_id: u32, address: u64)59 pub(crate) fn update_hpet_cfg(hpet_id: usize, timer_block_id: u32, address: u64) { 60 assert!(bql_locked()); 61 // SAFETY: all accesses go through these methods, which guarantee 62 // that the accesses are protected by the BQL. 63 let mut fw_cfg = unsafe { *addr_of_mut!(hpet_fw_cfg) }; 64 65 fw_cfg.hpet[hpet_id].event_timer_block_id = timer_block_id; 66 fw_cfg.hpet[hpet_id].address = address; 67 } 68 } 69