xref: /qemu/rust/hw/timer/hpet/src/fw_cfg.rs (revision 513823e7521a09ed7ad1e32e6454bac3b2cbf52d)
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 use std::ptr::addr_of_mut;
6 
7 use qemu_api::{cell::bql_locked, impl_zeroable, 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 impl_zeroable!(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 impl_zeroable!(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 {
39     pub(crate) fn assign_hpet_id() -> usize {
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             // TODO: Add error binding: error_setg()
52             panic!("Only 8 instances of HPET is allowed");
53         }
54 
55         let id: usize = fw_cfg.count.into();
56         fw_cfg.count += 1;
57         id
58     }
59 
60     pub(crate) fn update_hpet_cfg(hpet_id: usize, timer_block_id: u32, address: u64) {
61         assert!(bql_locked());
62         // SAFETY: all accesses go through these methods, which guarantee
63         // that the accesses are protected by the BQL.
64         let mut fw_cfg = unsafe { *addr_of_mut!(hpet_fw_cfg) };
65 
66         fw_cfg.hpet[hpet_id].event_timer_block_id = timer_block_id;
67         fw_cfg.hpet[hpet_id].address = address;
68     }
69 }
70