xref: /qemu/rust/hw/timer/hpet/src/fw_cfg.rs (revision 96215036f47403438c7c7869b7cd419bd7a11f82)
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