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