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